forked from shaba/openuds
upgraded os managers and typo fix
This commit is contained in:
parent
2b733c0e9e
commit
b233e26a52
@ -32,7 +32,7 @@
|
||||
"""
|
||||
import typing
|
||||
|
||||
# Not imported in runtime, just for type checking
|
||||
# Not imported at runtime, just for type checking
|
||||
if typing.TYPE_CHECKING:
|
||||
from .authenticator import Authenticator
|
||||
|
||||
|
@ -269,7 +269,7 @@ class Module(UserInterface, Environmentable, Serializable):
|
||||
Returns:
|
||||
Internacionalized (using ugettext) string of result of the check.
|
||||
"""
|
||||
return _("No check method provided.")
|
||||
return _("No check method provided.")
|
||||
|
||||
def getUuid(self) -> str:
|
||||
return self._uuid
|
||||
|
@ -42,7 +42,7 @@ from uds.core.transports import protocols
|
||||
from uds.core.util import encoders
|
||||
from uds.core.util import connection
|
||||
|
||||
# Not imported in runtime, just for type checking
|
||||
# Not imported at runtime, just for type checking
|
||||
if typing.TYPE_CHECKING:
|
||||
from django.http import HttpRequest # pylint: disable=ungrouped-imports
|
||||
from uds.core.environment import Environment
|
||||
|
@ -36,7 +36,7 @@ import typing
|
||||
from uds.models import Permissions
|
||||
from uds.core.util import ot
|
||||
|
||||
# Not imported in runtime, just for type checking
|
||||
# Not imported at runtime, just for type checking
|
||||
if typing.TYPE_CHECKING:
|
||||
from uds.models import User, Group
|
||||
|
||||
|
@ -40,7 +40,7 @@ from .util import NEVER
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Not imported in runtime, just for type checking
|
||||
# Not imported at runtime, just for type checking
|
||||
if typing.TYPE_CHECKING:
|
||||
from uds.models import UserService
|
||||
|
||||
|
@ -45,7 +45,7 @@ from .managed_object_model import ManagedObjectModel
|
||||
from .tag import TaggingMixin
|
||||
from .util import NEVER
|
||||
|
||||
# Not imported in runtime, just for type checking
|
||||
# Not imported at runtime, just for type checking
|
||||
if typing.TYPE_CHECKING:
|
||||
from .user import User
|
||||
from django.db.models import QuerySet # pylint: disable=ungrouped-imports
|
||||
|
@ -44,7 +44,7 @@ from .authenticator import Authenticator
|
||||
from .user import User
|
||||
from .util import UnsavedForeignKey, getSqlDatetime
|
||||
|
||||
# Not imported in runtime, just for type checking
|
||||
# Not imported at runtime, just for type checking
|
||||
if typing.TYPE_CHECKING:
|
||||
from uds.core import auths
|
||||
|
||||
|
@ -39,7 +39,7 @@ from django.db.models import signals
|
||||
from .managed_object_model import ManagedObjectModel
|
||||
from .tag import TaggingMixin
|
||||
|
||||
# Not imported in runtime, just for type checking
|
||||
# Not imported at runtime, just for type checking
|
||||
if typing.TYPE_CHECKING:
|
||||
from uds.core import osmanagers
|
||||
|
||||
|
@ -40,7 +40,7 @@ from uds.core.util import log
|
||||
from .managed_object_model import ManagedObjectModel
|
||||
from .tag import TaggingMixin
|
||||
|
||||
# Not imported in runtime, just for type checking
|
||||
# Not imported at runtime, just for type checking
|
||||
if typing.TYPE_CHECKING:
|
||||
from uds.core import services
|
||||
|
||||
|
@ -46,7 +46,7 @@ from .tag import TaggingMixin
|
||||
from .proxy import Proxy
|
||||
from .provider import Provider
|
||||
|
||||
# Not imported in runtime, just for type checking
|
||||
# Not imported at runtime, just for type checking
|
||||
if typing.TYPE_CHECKING:
|
||||
from uds.core import services
|
||||
|
||||
|
@ -60,7 +60,7 @@ from .util import NEVER
|
||||
from .util import getSqlDatetime
|
||||
|
||||
|
||||
# Not imported in runtime, just for type checking
|
||||
# Not imported at runtime, just for type checking
|
||||
if typing.TYPE_CHECKING:
|
||||
from uds.models import UserService, ServicePoolPublication, User
|
||||
|
||||
|
@ -44,7 +44,7 @@ from .util import NEVER
|
||||
from .util import getSqlDatetime
|
||||
from .uuid_model import UUIDModel
|
||||
|
||||
# Not imported in runtime, just for type checking
|
||||
# Not imported at runtime, just for type checking
|
||||
if typing.TYPE_CHECKING:
|
||||
from uds.core import auths
|
||||
from uds.models import Group
|
||||
|
@ -48,7 +48,7 @@ from .user import User
|
||||
from .util import NEVER
|
||||
from .util import getSqlDatetime
|
||||
|
||||
# Not imported in runtime, just for type checking
|
||||
# Not imported at runtime, just for type checking
|
||||
if typing.TYPE_CHECKING:
|
||||
from uds.core import services
|
||||
from uds.models import OSManager, ServicePool, ServicePoolPublication
|
||||
|
@ -1,96 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
|
||||
"""
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
"""
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.utils.translation import ugettext_noop as _
|
||||
from uds.core.ui import gui
|
||||
from uds.core.managers import cryptoManager
|
||||
from uds.core import osmanagers
|
||||
from .WindowsOsManager import WindowsOsManager
|
||||
from uds.core.util import log
|
||||
from uds.core.util import encoders
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class WinRandomPassManager(WindowsOsManager):
|
||||
typeName = _('Windows Random Password OS Manager')
|
||||
typeType = 'WinRandomPasswordManager'
|
||||
typeDescription = _('Os Manager to control windows machines, with user password set randomly.')
|
||||
iconFile = 'wosmanager.png'
|
||||
|
||||
# Apart form data from windows os manager, we need also domain and credentials
|
||||
userAccount = gui.TextField(length=64, label=_('Account'), order=2, tooltip=_('User account to change password'), required=True)
|
||||
password = gui.PasswordField(length=64, label=_('Password'), order=3, tooltip=_('Current (template) password of the user account'), required=True)
|
||||
|
||||
# Inherits base "onLogout"
|
||||
onLogout = WindowsOsManager.onLogout
|
||||
idle = WindowsOsManager.idle
|
||||
|
||||
def __init__(self, environment, values):
|
||||
super(WinRandomPassManager, self).__init__(environment, values)
|
||||
if values is not None:
|
||||
if values['userAccount'] == '':
|
||||
raise osmanagers.OSManager.ValidationException(_('Must provide an user account!!!'))
|
||||
if values['password'] == '':
|
||||
raise osmanagers.OSManager.ValidationException(_('Must provide a password for the account!!!'))
|
||||
self._userAccount = values['userAccount']
|
||||
self._password = values['password']
|
||||
else:
|
||||
self._userAccount = ''
|
||||
self._password = ""
|
||||
|
||||
def release(self, service):
|
||||
super(WinRandomPassManager, self).release(service)
|
||||
|
||||
def processUserPassword(self, service, username, password):
|
||||
if username == self._userAccount:
|
||||
password = service.recoverValue('winOsRandomPass')
|
||||
|
||||
return WindowsOsManager.processUserPassword(self, service, username, password)
|
||||
|
||||
def genPassword(self, service):
|
||||
import random
|
||||
import string
|
||||
randomPass = service.recoverValue('winOsRandomPass')
|
||||
if randomPass is None:
|
||||
randomPass = ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(16))
|
||||
service.storeValue('winOsRandomPass', randomPass)
|
||||
log.doLog(service, log.INFO, "Password set to \"{}\"".format(randomPass), log.OSMANAGER)
|
||||
return randomPass
|
||||
|
||||
def infoVal(self, service):
|
||||
return 'rename:{0}\t{1}\t{2}\t{3}'.format(self.getName(service), self._userAccount, self._password, self.genPassword(service))
|
||||
|
||||
def infoValue(self, service):
|
||||
return 'rename\r{0}\t{1}\t{2}\t{3}'.format(self.getName(service), self._userAccount, self._password, self.genPassword(service))
|
||||
|
||||
def marshal(self):
|
||||
base = super(WinRandomPassManager, self).marshal()
|
||||
'''
|
||||
Serializes the os manager data so we can store it in database
|
||||
'''
|
||||
return '\t'.join(['v1', self._userAccount, cryptoManager().encrypt(self._password), encoders.encode(base, 'hex', asText=True)]).encode('utf8')
|
||||
|
||||
def unmarshal(self, s):
|
||||
data = s.decode('utf8').split('\t')
|
||||
if data[0] == 'v1':
|
||||
self._userAccount = data[1]
|
||||
self._password = cryptoManager().decrypt(data[2])
|
||||
super(WinRandomPassManager, self).unmarshal(encoders.decode(data[3], 'hex'))
|
||||
|
||||
def valuesDict(self):
|
||||
dic = super(WinRandomPassManager, self).valuesDict()
|
||||
dic['userAccount'] = self._userAccount
|
||||
dic['password'] = self._password
|
||||
return dic
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012 Virtual Cable S.L.
|
||||
# Copyright (c) 2012-2019 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
#
|
||||
@ -31,23 +31,24 @@
|
||||
"""
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
"""
|
||||
|
||||
from django.utils.translation import ugettext_noop as _
|
||||
from uds.core.osmanagers.osmfactory import OSManagersFactory
|
||||
from uds.core.managers import downloadsManager
|
||||
from .WindowsOsManager import WindowsOsManager
|
||||
from .WinDomainOsManager import WinDomainOsManager
|
||||
from .WinRandomPassOsManager import WinRandomPassManager
|
||||
from uds.core import VERSION
|
||||
|
||||
import os.path
|
||||
import sys
|
||||
|
||||
OSManagersFactory.factory().insert(WindowsOsManager)
|
||||
OSManagersFactory.factory().insert(WinDomainOsManager)
|
||||
OSManagersFactory.factory().insert(WinRandomPassManager)
|
||||
from django.utils.translation import ugettext_noop as _
|
||||
from uds.core import osmanagers
|
||||
from uds.core import managers
|
||||
from uds.core import VERSION
|
||||
|
||||
downloadsManager().registerDownloadable('UDSActorSetup-{version}.exe'.format(version=VERSION),
|
||||
_('UDS Actor for windows machines'),
|
||||
os.path.dirname(sys.modules[__package__].__file__) + '/files/UDSActorSetup-{version}.exe'.format(version=VERSION),
|
||||
'application/x-msdos-program')
|
||||
from .windows import WindowsOsManager
|
||||
from .windows_domain import WinDomainOsManager
|
||||
from .windows_random import WinRandomPassManager
|
||||
|
||||
osmanagers.factory().insert(WindowsOsManager)
|
||||
osmanagers.factory().insert(WinDomainOsManager)
|
||||
osmanagers.factory().insert(WinRandomPassManager)
|
||||
|
||||
managers.downloadsManager().registerDownloadable(
|
||||
'UDSActorSetup-{version}.exe'.format(version=VERSION),
|
||||
_('UDS Actor for windows machines'),
|
||||
os.path.dirname(sys.modules[__package__].__file__) + '/files/UDSActorSetup-{version}.exe'.format(version=VERSION),
|
||||
'application/x-msdos-program')
|
||||
|
@ -12,34 +12,33 @@ import logging
|
||||
import typing
|
||||
|
||||
from django.utils.translation import ugettext_noop as _, ugettext_lazy
|
||||
from uds.core import osmanagers
|
||||
from uds.core.services import types as serviceTypes
|
||||
from uds.core.ui import gui
|
||||
from uds.core import osmanagers
|
||||
from uds.core.managers import userServiceManager
|
||||
from uds.core.util.state import State
|
||||
from uds.core.util import encoders
|
||||
from uds.core.util import log
|
||||
from uds.models import TicketStore
|
||||
|
||||
# Not imported in runtime, just for type checking
|
||||
# Not imported at runtime, just for type checking
|
||||
if typing.TYPE_CHECKING:
|
||||
from uds.models import UserService
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def scrambleMsg(data):
|
||||
def scrambleMsg(msg: str) -> str:
|
||||
"""
|
||||
Simple scrambler so password are not seen at source page
|
||||
"""
|
||||
if isinstance(data, str):
|
||||
data = data.encode('utf8')
|
||||
res = []
|
||||
data = msg.encode('utf8')
|
||||
res = b''
|
||||
n = 0x32
|
||||
for c in data[::-1]:
|
||||
res.append(chr(ord(c) ^ n))
|
||||
n = (n + ord(c)) & 0xFF
|
||||
return (b''.join(res).encode('hex')).decode('utf8')
|
||||
res += bytes([c ^ n])
|
||||
n = (n + c) & 0xFF
|
||||
return typing.cast(str, encoders.encode(res, 'hex', asText=True))
|
||||
|
||||
|
||||
class WindowsOsManager(osmanagers.OSManager):
|
||||
@ -100,61 +99,61 @@ class WindowsOsManager(osmanagers.OSManager):
|
||||
'''
|
||||
Says if a machine is removable on logout
|
||||
'''
|
||||
if userService.in_use == False:
|
||||
if not userService.in_use:
|
||||
if (self._onLogout == 'remove') or (not userService.isValidPublication() and self._onLogout == 'keep'):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def release(self, service):
|
||||
def release(self, userService: 'UserService') -> None:
|
||||
pass
|
||||
|
||||
def getName(self, service):
|
||||
def getName(self, userService: 'UserService') -> str:
|
||||
"""
|
||||
gets name from deployed
|
||||
"""
|
||||
return service.getName()
|
||||
return userService.getName()
|
||||
|
||||
def infoVal(self, service):
|
||||
return 'rename:' + self.getName(service)
|
||||
def infoVal(self, userService: 'UserService') -> str:
|
||||
return 'rename:' + self.getName(userService)
|
||||
|
||||
def infoValue(self, service):
|
||||
return 'rename\r' + self.getName(service)
|
||||
def infoValue(self, userService: 'UserService') -> str:
|
||||
return 'rename\r' + self.getName(userService)
|
||||
|
||||
def notifyIp(self, uid, service, data):
|
||||
si = service.getInstance()
|
||||
def notifyIp(self, uid: str, userService, data: typing.Dict[str, typing.Any]) -> None:
|
||||
userServiceInstance = userService.getInstance()
|
||||
|
||||
ip = ''
|
||||
# Notifies IP to deployed
|
||||
for p in data['ips']:
|
||||
if p[0].lower() == uid.lower():
|
||||
si.setIp(p[1])
|
||||
userServiceInstance.setIp(p[1])
|
||||
ip = p[1]
|
||||
break
|
||||
|
||||
self.logKnownIp(service, ip)
|
||||
service.updateData(si)
|
||||
self.logKnownIp(userService, ip)
|
||||
userService.updateData(userServiceInstance)
|
||||
|
||||
def doLog(self, service, data, origin=log.OSMANAGER):
|
||||
def doLog(self, userService: 'UserService', data: str, origin=log.OSMANAGER):
|
||||
# Stores a log associated with this service
|
||||
try:
|
||||
msg, level = data.split('\t')
|
||||
msg, levelStr = data.split('\t')
|
||||
try:
|
||||
level = int(level)
|
||||
level = int(levelStr)
|
||||
except Exception:
|
||||
logger.debug('Do not understand level {}'.format(level))
|
||||
logger.debug('Do not understand level %s', level)
|
||||
level = log.INFO
|
||||
|
||||
log.doLog(service, level, msg, origin)
|
||||
log.doLog(userService, level, msg, origin)
|
||||
except Exception:
|
||||
logger.exception('WindowsOs Manager message log: ')
|
||||
log.doLog(service, log.ERROR, "do not understand {0}".format(data), origin)
|
||||
log.doLog(userService, log.ERROR, "do not understand {0}".format(data), origin)
|
||||
|
||||
# default "ready received" does nothing
|
||||
def readyReceived(self, userService, data):
|
||||
pass
|
||||
|
||||
def process(self, userService: 'UserService', msg, data, options=None):
|
||||
def process(self, userService: 'UserService', message: str, data: typing.Any, options: typing.Optional[typing.Dict[str, typing.Any]] = None) -> str: # pylint: disable=too-many-branches
|
||||
"""
|
||||
We understand this messages:
|
||||
* msg = info, data = None. Get information about name of machine (or domain, in derived WinDomainOsManager class) (old method)
|
||||
@ -163,29 +162,28 @@ class WindowsOsManager(osmanagers.OSManager):
|
||||
* msg = logoff, data = Username, Informs that the username has logged out of the machine
|
||||
* msg = ready, data = None, Informs machine ready to be used
|
||||
"""
|
||||
logger.info("Invoked WindowsOsManager for {0} with params: {1},{2}".format(userService, msg, data))
|
||||
logger.info("Invoked WindowsOsManager for %s with params: %s,%s", userService, message, data)
|
||||
|
||||
if msg in ('ready', 'ip'):
|
||||
if not isinstance(data, dict): # Old actors, previous to 2.5, convert it information..
|
||||
data = {
|
||||
'ips': [v.split('=') for v in data.split(',')],
|
||||
'hostname': userService.friendly_name
|
||||
}
|
||||
if message in ('ready', 'ip') and not isinstance(data, dict): # Old actors, previous to 2.5, convert it information..
|
||||
data = {
|
||||
'ips': [v.split('=') for v in data.split(',')],
|
||||
'hostname': userService.friendly_name
|
||||
}
|
||||
|
||||
# We get from storage the name for this userService. If no name, we try to assign a new one
|
||||
ret = "ok"
|
||||
notifyReady = False
|
||||
doRemove = False
|
||||
state = userService.os_state
|
||||
if msg == "info":
|
||||
if message == "info":
|
||||
ret = self.infoVal(userService)
|
||||
state = State.PREPARING
|
||||
elif msg == "information":
|
||||
elif message == "information":
|
||||
ret = self.infoValue(userService)
|
||||
state = State.PREPARING
|
||||
elif msg == "log":
|
||||
elif message == "log":
|
||||
self.doLog(userService, data, log.ACTOR)
|
||||
elif msg == "logon" or msg == 'login':
|
||||
elif message in("logon", 'login'):
|
||||
if '\\' not in data:
|
||||
self.loggedIn(userService, data)
|
||||
userService.setInUse(True)
|
||||
@ -196,14 +194,14 @@ class WindowsOsManager(osmanagers.OSManager):
|
||||
ret = "{0}\t{1}\t{2}".format(ip, hostname, 0 if deadLine is None else deadLine)
|
||||
else:
|
||||
ret = "{0}\t{1}".format(ip, hostname)
|
||||
elif msg in ('logoff', 'logout'):
|
||||
elif message in ('logoff', 'logout'):
|
||||
self.loggedOut(userService, data)
|
||||
doRemove = self.isRemovableOnLogout(userService)
|
||||
elif msg == "ip":
|
||||
elif message == "ip":
|
||||
# This ocurss on main loop inside machine, so userService is usable
|
||||
state = State.USABLE
|
||||
self.notifyIp(userService.unique_id, userService, data)
|
||||
elif msg == "ready":
|
||||
elif message == "ready":
|
||||
self.toReady(userService)
|
||||
state = State.USABLE
|
||||
notifyReady = True
|
||||
@ -221,13 +219,13 @@ class WindowsOsManager(osmanagers.OSManager):
|
||||
else:
|
||||
logger.debug('Notifying ready')
|
||||
userServiceManager().notifyReadyFromOsManager(userService, '')
|
||||
logger.debug('Returning {} to {} message'.format(ret, msg))
|
||||
logger.debug('Returning %s to %s message', ret, message)
|
||||
if options is not None and options.get('scramble', True) is False:
|
||||
return ret
|
||||
return scrambleMsg(ret)
|
||||
|
||||
def processUserPassword(self, service, username, password):
|
||||
if service.getProperty('sso_available') == '1':
|
||||
def processUserPassword(self, userService: 'UserService', username: str, password: str) -> typing.Tuple[str, str]:
|
||||
if userService.getProperty('sso_available') == '1':
|
||||
# Generate a ticket, store it and return username with no password
|
||||
domain = ''
|
||||
if '@' in username:
|
||||
@ -242,10 +240,10 @@ class WindowsOsManager(osmanagers.OSManager):
|
||||
}
|
||||
ticket = TicketStore.create(creds, validator=None, validity=300) # , owner=SECURE_OWNER, secure=True)
|
||||
return ticket, ''
|
||||
else:
|
||||
return osmanagers.OSManager.processUserPassword(self, service, username, password)
|
||||
|
||||
def processUnused(self, userService):
|
||||
return osmanagers.OSManager.processUserPassword(self, userService, username, password)
|
||||
|
||||
def processUnused(self, userService: 'UserService') -> None:
|
||||
"""
|
||||
This will be invoked for every assigned and unused user service that has been in this state at least 1/2 of Globalconfig.CHECK_UNUSED_TIME
|
||||
This function can update userService values. Normal operation will be remove machines if this state is not valid
|
||||
@ -256,8 +254,9 @@ class WindowsOsManager(osmanagers.OSManager):
|
||||
def isPersistent(self):
|
||||
return self._onLogout == 'keep-always'
|
||||
|
||||
def checkState(self, service):
|
||||
logger.debug('Checking state for service {0}'.format(service))
|
||||
def checkState(self, userService: 'UserService') -> str:
|
||||
# will alway return true, because the check is done by an actor callback
|
||||
logger.debug('Checking state for service %s', userService)
|
||||
return State.RUNNING
|
||||
|
||||
def maxIdle(self):
|
||||
@ -269,24 +268,24 @@ class WindowsOsManager(osmanagers.OSManager):
|
||||
|
||||
return self._idle
|
||||
|
||||
def marshal(self):
|
||||
def marshal(self) -> bytes:
|
||||
"""
|
||||
Serializes the os manager data so we can store it in database
|
||||
"""
|
||||
return '\t'.join(['v2', self._onLogout, str(self._idle)]).encode('utf8')
|
||||
|
||||
def unmarshal(self, s):
|
||||
data = s.decode('utf8').split('\t')
|
||||
def unmarshal(self, data: bytes) -> None:
|
||||
vals = data.decode('utf8').split('\t')
|
||||
try:
|
||||
if data[0] == 'v1':
|
||||
self._onLogout = data[1]
|
||||
if vals[0] == 'v1':
|
||||
self._onLogout = vals[1]
|
||||
self._idle = -1
|
||||
elif data[0] == 'v2':
|
||||
self._onLogout, self._idle = data[1], int(data[2])
|
||||
elif vals[0] == 'v2':
|
||||
self._onLogout, self._idle = vals[1], int(vals[2])
|
||||
except Exception:
|
||||
logger.exception('Exception unmarshalling. Some values left as default ones')
|
||||
|
||||
self.__setProcessUnusedMachines()
|
||||
|
||||
def valuesDict(self):
|
||||
def valuesDict(self) -> gui.ValuesDictType:
|
||||
return {'onLogout': self._onLogout, 'idle': self._idle}
|
@ -1,14 +1,38 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012 Virtual Cable S.L.
|
||||
# Copyright (c) 2012-2019 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
"""
|
||||
import logging
|
||||
import typing
|
||||
|
||||
import dns.resolver
|
||||
import ldap
|
||||
@ -21,7 +45,13 @@ from uds.core.util import log
|
||||
from uds.core.util import encoders
|
||||
from uds.core.util import ldaputil
|
||||
|
||||
from .WindowsOsManager import WindowsOsManager
|
||||
from .windows import WindowsOsManager
|
||||
|
||||
# Not imported at runtime, just for type checking
|
||||
if typing.TYPE_CHECKING:
|
||||
from uds.core import Module
|
||||
from uds.core.environment import Environment
|
||||
from uds.models import UserService
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -42,14 +72,23 @@ class WinDomainOsManager(WindowsOsManager):
|
||||
removeOnExit = gui.CheckBoxField(label=_('Machine clean'), order=8, tooltip=_('If checked, UDS will try to remove the machine from the domain USING the provided credentials'), tab=_('Advanced'), defvalue=gui.TRUE)
|
||||
serverHint = gui.TextField(length=64, label=_('Server Hint'), order=9, tooltip=_('In case of several AD servers, which one is preferred'), tab=_('Advanced'))
|
||||
ssl = gui.CheckBoxField(label=_('Use SSL'), order=10, tooltip=_('If checked, a ssl connection to Active Directory will be used'), tab=_('Advanced'))
|
||||
|
||||
|
||||
# Inherits base "onLogout"
|
||||
onLogout = WindowsOsManager.onLogout
|
||||
idle = WindowsOsManager.idle
|
||||
|
||||
def __init__(self, environment, values):
|
||||
super(WinDomainOsManager, self).__init__(environment, values)
|
||||
if values is not None:
|
||||
_domain: str
|
||||
_ou: str
|
||||
_account: str
|
||||
_pasword: str
|
||||
_group: str
|
||||
_serverHint: str
|
||||
_removeOnExit: str
|
||||
_ssl: str
|
||||
|
||||
def __init__(self, environment: 'Environment', values: 'Module.ValuesType'):
|
||||
super().__init__(environment, values)
|
||||
if values:
|
||||
if values['domain'] == '':
|
||||
raise osmanagers.OSManager.ValidationException(_('Must provide a domain!'))
|
||||
# if values['domain'].find('.') == -1:
|
||||
@ -66,8 +105,8 @@ class WinDomainOsManager(WindowsOsManager):
|
||||
self._password = values['password']
|
||||
self._group = values['grp'].strip()
|
||||
self._serverHint = values['serverHint'].strip()
|
||||
self._ssl = 'y' if values['ssl'] else 'n'
|
||||
self._removeOnExit = 'y' if values['removeOnExit'] else 'n'
|
||||
self._ssl = 'y' if values['ssl'] else 'n'
|
||||
self._removeOnExit = 'y' if values['removeOnExit'] else 'n'
|
||||
else:
|
||||
self._domain = ""
|
||||
self._ou = ""
|
||||
@ -84,14 +123,14 @@ class WinDomainOsManager(WindowsOsManager):
|
||||
if self._ou.lower().find(lpath) == -1:
|
||||
self._ou += ',' + lpath
|
||||
|
||||
def __getServerList(self):
|
||||
def __getServerList(self) -> typing.Iterable[typing.Tuple[str, int]]:
|
||||
if self._serverHint != '':
|
||||
yield (self._serverHint, 389)
|
||||
|
||||
for server in reversed(sorted(dns.resolver.query('_ldap._tcp.' + self._domain, 'SRV'), key=lambda i: i.priority * 10000 + i.weight)):
|
||||
yield (str(server.target)[:-1], server.port)
|
||||
|
||||
def __connectLdap(self, servers=None):
|
||||
def __connectLdap(self, servers: typing.Optional[typing.Iterable[typing.Tuple[str, int]]] = None) -> typing.Any:
|
||||
"""
|
||||
Tries to connect to LDAP
|
||||
Raises an exception if not found:
|
||||
@ -108,8 +147,8 @@ class WinDomainOsManager(WindowsOsManager):
|
||||
_str = "No servers found"
|
||||
# And if not possible, try using NON-SSL
|
||||
for server in servers:
|
||||
port = server[1] if self._ssl != 'y' else -1
|
||||
ssl = self._ssl == 'y'
|
||||
port = server[1] if not ssl else -1
|
||||
try:
|
||||
return ldaputil.connection(account, self._password, server[0], port, ssl=ssl, timeout=10, debug=False)
|
||||
except Exception as e:
|
||||
@ -117,11 +156,11 @@ class WinDomainOsManager(WindowsOsManager):
|
||||
|
||||
raise ldaputil.LDAPError(_str)
|
||||
|
||||
def __getGroup(self, l):
|
||||
def __getGroup(self, ldapConnection: typing.Any) -> str:
|
||||
base = ','.join(['DC=' + i for i in self._domain.split('.')])
|
||||
group = ldaputil.escape(self._group)
|
||||
try:
|
||||
obj = next(ldaputil.getAsDict(l, base, "(&(objectClass=group)(|(cn={0})(sAMAccountName={0})))".format(group), ['dn'], sizeLimit=50))
|
||||
obj = next(ldaputil.getAsDict(ldapConnection, base, "(&(objectClass=group)(|(cn={0})(sAMAccountName={0})))".format(group), ['dn'], sizeLimit=50))
|
||||
except StopIteration:
|
||||
obj = None
|
||||
|
||||
@ -130,7 +169,7 @@ class WinDomainOsManager(WindowsOsManager):
|
||||
|
||||
return obj['dn'] # Returns the DN
|
||||
|
||||
def __getMachine(self, l, machineName):
|
||||
def __getMachine(self, ldapConnection, machineName: str) -> typing.Optional[str]:
|
||||
# if self._ou:
|
||||
# base = self._ou
|
||||
# else:
|
||||
@ -138,7 +177,7 @@ class WinDomainOsManager(WindowsOsManager):
|
||||
|
||||
fltr = '(&(objectClass=computer)(sAMAccountName={}$))'.format(ldaputil.escape(machineName))
|
||||
try:
|
||||
obj = next(ldaputil.getAsDict(l, base, fltr, ['dn'], sizeLimit=50))
|
||||
obj = next(ldaputil.getAsDict(ldapConnection, base, fltr, ['dn'], sizeLimit=50))
|
||||
except StopIteration:
|
||||
obj = None
|
||||
|
||||
@ -147,29 +186,27 @@ class WinDomainOsManager(WindowsOsManager):
|
||||
|
||||
return obj['dn'] # Returns the DN
|
||||
|
||||
def readyReceived(self, userService, data):
|
||||
def readyReceived(self, userService: 'UserService', data: str) -> None:
|
||||
# No group to add
|
||||
if self._group == '':
|
||||
return
|
||||
|
||||
if not '.' in self._domain:
|
||||
if '.' not in self._domain:
|
||||
logger.info('Adding to a group for a non FQDN domain is not supported')
|
||||
return
|
||||
|
||||
# The machine is on a AD for sure, and maybe they are not already sync
|
||||
servers = list(self.__getServerList())
|
||||
|
||||
error = None
|
||||
for s in servers:
|
||||
error: typing.Optional[str] = None
|
||||
for s in self.__getServerList():
|
||||
try:
|
||||
l = self.__connectLdap(servers=(s,))
|
||||
ldapConnection = self.__connectLdap(servers=(s,))
|
||||
|
||||
machine = self.__getMachine(l, userService.friendly_name)
|
||||
group = self.__getGroup(l)
|
||||
machine = self.__getMachine(ldapConnection, userService.friendly_name)
|
||||
group = self.__getGroup(ldapConnection)
|
||||
# #
|
||||
# Direct LDAP operation "modify", maybe this need to be added to ldaputil? :)
|
||||
# #
|
||||
l.modify_s(group, ((ldap.MOD_ADD, 'member', machine),)) # @UndefinedVariable
|
||||
ldapConnection.modify_s(group, ((ldap.MOD_ADD, 'member', machine),)) # @UndefinedVariable
|
||||
error = None
|
||||
break
|
||||
except dns.resolver.NXDOMAIN: # No domain found, log it and pass
|
||||
@ -186,16 +223,13 @@ class WinDomainOsManager(WindowsOsManager):
|
||||
error = "Could not add machine {} to group {}: {}".format(userService.friendly_name, self._group, e)
|
||||
# logger.exception('Ldap Exception caught')
|
||||
|
||||
if error is not None:
|
||||
if error:
|
||||
log.doLog(userService, log.WARN, error, log.OSMANAGER)
|
||||
logger.error(error)
|
||||
|
||||
def release(self, service):
|
||||
"""
|
||||
service is a db user service object
|
||||
"""
|
||||
super(WinDomainOsManager, self).release(service)
|
||||
|
||||
def release(self, userService: 'UserSrevice') -> None:
|
||||
super().release(userService)
|
||||
|
||||
# If no removal requested, just return
|
||||
if self._removeOnExit != 'y':
|
||||
return
|
||||
@ -205,62 +239,62 @@ class WinDomainOsManager(WindowsOsManager):
|
||||
return
|
||||
|
||||
try:
|
||||
l = self.__connectLdap()
|
||||
ldapConnection = self.__connectLdap()
|
||||
except dns.resolver.NXDOMAIN: # No domain found, log it and pass
|
||||
logger.warning('Could not find _ldap._tcp.%s', self._domain)
|
||||
log.doLog(service, log.WARN, "Could not remove machine from domain (_ldap._tcp.{0} not found)".format(self._domain), log.OSMANAGER)
|
||||
log.doLog(userService, log.WARN, "Could not remove machine from domain (_ldap._tcp.{0} not found)".format(self._domain), log.OSMANAGER)
|
||||
return
|
||||
except ldaputil.LDAPError:
|
||||
logger.exception('Ldap Exception caught')
|
||||
log.doLog(service, log.WARN, "Could not remove machine from domain (invalid credentials for {0})".format(self._account), log.OSMANAGER)
|
||||
log.doLog(userService, log.WARN, "Could not remove machine from domain (invalid credentials for {0})".format(self._account), log.OSMANAGER)
|
||||
return
|
||||
except Exception:
|
||||
logger.exception('Exception caught')
|
||||
return
|
||||
|
||||
try:
|
||||
res = self.__getMachine(l, service.friendly_name)
|
||||
res = self.__getMachine(ldapConnection, userService.friendly_name)
|
||||
if res is None:
|
||||
raise Exception('Machine {} not found on AD (permissions?)'.format(service.friendly_name))
|
||||
ldaputil.recursive_delete(l, res)
|
||||
raise Exception('Machine {} not found on AD (permissions?)'.format(userService.friendly_name))
|
||||
ldaputil.recursive_delete(ldapConnection, res)
|
||||
except IndexError:
|
||||
logger.error('Error deleting %s from BASE %s', service.friendly_name, self._ou)
|
||||
logger.error('Error deleting %s from BASE %s', userService.friendly_name, self._ou)
|
||||
except Exception:
|
||||
logger.exception('Deleting from AD: ')
|
||||
|
||||
def check(self):
|
||||
def check(self) -> str:
|
||||
try:
|
||||
l = self.__connectLdap()
|
||||
ldapConnection = self.__connectLdap()
|
||||
except ldaputil.LDAPError as e:
|
||||
return _('Check error: {0}').format(self.__getLdapError(e))
|
||||
return _('Check error: {}').format(self.__getLdapError(e))
|
||||
except dns.resolver.NXDOMAIN:
|
||||
return [True, _('Could not find server parameters (_ldap._tcp.{0} can\'t be resolved)').format(self._domain)]
|
||||
return _('Could not find server parameters (_ldap._tcp.{0} can\'t be resolved)').format(self._domain)
|
||||
except Exception as e:
|
||||
logger.exception('Exception ')
|
||||
return [False, str(e)]
|
||||
return str(e)
|
||||
|
||||
try:
|
||||
l.search_st(self._ou, ldap.SCOPE_BASE) # @UndefinedVariable
|
||||
ldapConnection.search_st(self._ou, ldap.SCOPE_BASE) # @UndefinedVariable
|
||||
except ldaputil.LDAPError as e:
|
||||
return _('Check error: {0}').format(self.__getLdapError(e))
|
||||
return _('Check error: {}').format(self.__getLdapError(e))
|
||||
|
||||
# Group
|
||||
if self._group != '':
|
||||
if self.__getGroup(l) is None:
|
||||
if self.__getGroup(ldapConnection) is None:
|
||||
return _('Check Error: group "{}" not found (using "cn" to locate it)').format(self._group)
|
||||
|
||||
return _('Server check was successful')
|
||||
|
||||
# pylint: disable=protected-access
|
||||
@staticmethod
|
||||
def test(env, data):
|
||||
def test(env: 'Environment', data: typing.Dict[str, str]) -> typing.List[typing.Any]:
|
||||
logger.debug('Test invoked')
|
||||
wd = None
|
||||
wd: typing.Optional[WinDomainOsManager] = None
|
||||
try:
|
||||
wd = WinDomainOsManager(env, data)
|
||||
logger.debug(wd)
|
||||
try:
|
||||
l = wd.__connectLdap()
|
||||
ldapConnection = wd.__connectLdap()
|
||||
except ldaputil.LDAPError as e:
|
||||
return [False, _('Could not access AD using LDAP ({0})').format(wd.__getLdapError(e))]
|
||||
|
||||
@ -268,15 +302,14 @@ class WinDomainOsManager(WindowsOsManager):
|
||||
if ou == '':
|
||||
ou = 'cn=Computers,dc=' + ',dc='.join(wd._domain.split('.'))
|
||||
|
||||
logger.debug('Checking {0} with ou {1}'.format(wd._domain, ou))
|
||||
r = l.search_st(ou, ldap.SCOPE_BASE) # @UndefinedVariable
|
||||
logger.debug('Result of search: {0}'.format(r))
|
||||
logger.info('Checking %s with ou %s', wd._domain, ou)
|
||||
r = ldapConnection.search_st(ou, ldap.SCOPE_BASE) # @UndefinedVariable
|
||||
logger.info('Result of search: %s', r)
|
||||
|
||||
except ldaputil.LDAPError:
|
||||
if wd._ou == '':
|
||||
if not wd._ou:
|
||||
return [False, _('The default path {0} for computers was not found!!!').format(wd._ou)]
|
||||
else:
|
||||
return [False, _('The ou path {0} was not found!!!').format(wd._ou)]
|
||||
return [False, _('The ou path {0} was not found!!!').format(wd._ou)]
|
||||
except dns.resolver.NXDOMAIN:
|
||||
return [True, _('Could not check parameters (_ldap._tcp.{0} can\'r be resolved)').format(wd._domain)]
|
||||
except Exception as e:
|
||||
@ -285,54 +318,54 @@ class WinDomainOsManager(WindowsOsManager):
|
||||
|
||||
return [True, _("All parameters seem to work fine.")]
|
||||
|
||||
def infoVal(self, service):
|
||||
return 'domain:{0}\t{1}\t{2}\t{3}\t{4}'.format(self.getName(service), self._domain, self._ou, self._account, self._password)
|
||||
def infoVal(self, userService: 'UserService') -> str:
|
||||
return 'domain:{0}\t{1}\t{2}\t{3}\t{4}'.format(self.getName(userService), self._domain, self._ou, self._account, self._password)
|
||||
|
||||
def infoValue(self, service):
|
||||
return 'domain\r{0}\t{1}\t{2}\t{3}\t{4}'.format(self.getName(service), self._domain, self._ou, self._account, self._password)
|
||||
def infoValue(self, userService: 'UserService') -> str:
|
||||
return 'domain\r{0}\t{1}\t{2}\t{3}\t{4}'.format(self.getName(userService), self._domain, self._ou, self._account, self._password)
|
||||
|
||||
def marshal(self):
|
||||
base = super(WinDomainOsManager, self).marshal()
|
||||
def marshal(self) -> bytes:
|
||||
'''
|
||||
Serializes the os manager data so we can store it in database
|
||||
'''
|
||||
base = typing.cast(str, encoders.encode(super().marshal(), 'hex', asText=True))
|
||||
return '\t'.join([
|
||||
'v4',
|
||||
self._domain, self._ou, self._account,
|
||||
cryptoManager().encrypt(self._password),
|
||||
encoders.encode(base, 'hex', asText=True),
|
||||
self._group, self._serverHint, self._ssl, self._removeOnExit]
|
||||
).encode('utf8')
|
||||
base,
|
||||
self._group, self._serverHint, self._ssl, self._removeOnExit
|
||||
]).encode('utf8')
|
||||
|
||||
def unmarshal(self, s):
|
||||
data = s.decode('utf8').split('\t')
|
||||
if data[0] in ('v1', 'v2', 'v3', 'v4'):
|
||||
self._domain = data[1]
|
||||
self._ou = data[2]
|
||||
self._account = data[3]
|
||||
self._password = cryptoManager().decrypt(data[4])
|
||||
def unmarshal(self, data: bytes) -> None:
|
||||
values = data.decode('utf8').split('\t')
|
||||
if values[0] in ('v1', 'v2', 'v3', 'v4'):
|
||||
self._domain = values[1]
|
||||
self._ou = values[2]
|
||||
self._account = values[3]
|
||||
self._password = cryptoManager().decrypt(values[4])
|
||||
|
||||
if data[0] in ('v2', 'v3', 'v4'):
|
||||
self._group = data[6]
|
||||
if values[0] in ('v2', 'v3', 'v4'):
|
||||
self._group = values[6]
|
||||
else:
|
||||
self._group = ''
|
||||
|
||||
if data[0] in ('v3', 'v4'):
|
||||
self._serverHint = data[7]
|
||||
if values[0] in ('v3', 'v4'):
|
||||
self._serverHint = values[7]
|
||||
else:
|
||||
self._serverHint = ''
|
||||
|
||||
if data[0] == 'v4':
|
||||
self._ssl = data[8]
|
||||
self._removeOnExit = data[9]
|
||||
if values[0] == 'v4':
|
||||
self._ssl = values[8]
|
||||
self._removeOnExit = values[9]
|
||||
else:
|
||||
self._ssl = 'n'
|
||||
self._removeOnExit = 'y'
|
||||
|
||||
super(WinDomainOsManager, self).unmarshal(encoders.decode(data[5], 'hex'))
|
||||
super().unmarshal(typing.cast(bytes, encoders.decode(values[5], 'hex')))
|
||||
|
||||
def valuesDict(self):
|
||||
dct = super(WinDomainOsManager, self).valuesDict()
|
||||
def valuesDict(self) -> gui.ValuesDictType:
|
||||
dct = super().valuesDict()
|
||||
dct['domain'] = self._domain
|
||||
dct['ou'] = self._ou
|
||||
dct['account'] = self._account
|
123
server/src/uds/osmanagers/WindowsOsManager/windows_random.py
Normal file
123
server/src/uds/osmanagers/WindowsOsManager/windows_random.py
Normal file
@ -0,0 +1,123 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012-2019 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
"""
|
||||
import random
|
||||
import string
|
||||
import logging
|
||||
import typing
|
||||
|
||||
from django.utils.translation import ugettext_noop as _
|
||||
from uds.core.ui import gui
|
||||
from uds.core.managers import cryptoManager
|
||||
from uds.core import osmanagers
|
||||
from uds.core.util import log
|
||||
from uds.core.util import encoders
|
||||
|
||||
from .windows import WindowsOsManager
|
||||
|
||||
# Not imported at runtime, just for type checking
|
||||
if typing.TYPE_CHECKING:
|
||||
from uds.core import Module
|
||||
from uds.core.environment import Environment
|
||||
from uds.models import UserService
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class WinRandomPassManager(WindowsOsManager):
|
||||
typeName = _('Windows Random Password OS Manager')
|
||||
typeType = 'WinRandomPasswordManager'
|
||||
typeDescription = _('Os Manager to control windows machines, with user password set randomly.')
|
||||
iconFile = 'wosmanager.png'
|
||||
|
||||
# Apart form data from windows os manager, we need also domain and credentials
|
||||
userAccount = gui.TextField(length=64, label=_('Account'), order=2, tooltip=_('User account to change password'), required=True)
|
||||
password = gui.PasswordField(length=64, label=_('Password'), order=3, tooltip=_('Current (template) password of the user account'), required=True)
|
||||
|
||||
# Inherits base "onLogout"
|
||||
onLogout = WindowsOsManager.onLogout
|
||||
idle = WindowsOsManager.idle
|
||||
|
||||
def __init__(self, environment: 'Environment', values: 'Module.ValuesType'):
|
||||
super().__init__(environment, values)
|
||||
if values:
|
||||
if values['userAccount'] == '':
|
||||
raise osmanagers.OSManager.ValidationException(_('Must provide an user account!!!'))
|
||||
if values['password'] == '':
|
||||
raise osmanagers.OSManager.ValidationException(_('Must provide a password for the account!!!'))
|
||||
self._userAccount = values['userAccount']
|
||||
self._password = values['password']
|
||||
else:
|
||||
self._userAccount = ''
|
||||
self._password = ""
|
||||
|
||||
def processUserPassword(self, userService: 'UserService', username: str, password: str) -> typing.Tuple[str, str]:
|
||||
if username == self._userAccount:
|
||||
password = userService.recoverValue('winOsRandomPass')
|
||||
|
||||
return WindowsOsManager.processUserPassword(self, userService, username, password)
|
||||
|
||||
def genPassword(self, userService: 'UserService'):
|
||||
randomPass = userService.recoverValue('winOsRandomPass')
|
||||
if not randomPass:
|
||||
randomPass = ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(16))
|
||||
userService.storeValue('winOsRandomPass', randomPass)
|
||||
log.doLog(userService, log.INFO, "Password set to \"{}\"".format(randomPass), log.OSMANAGER)
|
||||
return randomPass
|
||||
|
||||
def infoVal(self, userService: 'UserService') -> str:
|
||||
return 'rename:{0}\t{1}\t{2}\t{3}'.format(self.getName(userService), self._userAccount, self._password, self.genPassword(userService))
|
||||
|
||||
def infoValue(self, userService: 'UserService') -> str:
|
||||
return 'rename\r{0}\t{1}\t{2}\t{3}'.format(self.getName(userService), self._userAccount, self._password, self.genPassword(userService))
|
||||
|
||||
def marshal(self) -> bytes:
|
||||
'''
|
||||
Serializes the os manager data so we can store it in database
|
||||
'''
|
||||
base = typing.cast(str, encoders.encode(super().marshal(), 'hex', asText=True))
|
||||
return '\t'.join(['v1', self._userAccount, cryptoManager().encrypt(self._password), base]).encode('utf8')
|
||||
|
||||
def unmarshal(self, data: bytes) -> None:
|
||||
values = data.decode('utf8').split('\t')
|
||||
if values[0] == 'v1':
|
||||
self._userAccount = values[1]
|
||||
self._password = cryptoManager().decrypt(values[2])
|
||||
super().unmarshal(typing.cast(bytes, encoders.decode(values[3], 'hex')))
|
||||
|
||||
def valuesDict(self) -> gui.ValuesDictType:
|
||||
dic = super().valuesDict()
|
||||
dic['userAccount'] = self._userAccount
|
||||
dic['password'] = self._password
|
||||
return dic
|
@ -41,7 +41,7 @@ from uds.core.util import html
|
||||
|
||||
from uds.core.managers import userServiceManager
|
||||
|
||||
# Not imported in runtime, just for type checking
|
||||
# Not imported at runtime, just for type checking
|
||||
if typing.TYPE_CHECKING:
|
||||
from django.http import HttpRequest # pylint: disable=ungrouped-imports
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user