diff --git a/server/src/uds/REST/methods/actor.py b/server/src/uds/REST/methods/actor.py index f53d3a06..e9da34b2 100644 --- a/server/src/uds/REST/methods/actor.py +++ b/server/src/uds/REST/methods/actor.py @@ -65,6 +65,9 @@ ERR_HOST_NOT_MANAGED = 2 ERR_USER_SERVICE_NOT_FOUND = 3 ERR_OSMANAGER_ERROR = 4 +# Constants for tickets +OWNER = 'ACTOR' +SECURE_OWNER = 'SACTOR' # Enclosed methods under /actor path class Actor(Handler): @@ -132,17 +135,24 @@ class Actor(Handler): raise RequestError('Invalid request') try: - return Actor.result(TicketStore.get(self._args[1], invalidate=True, secure=secure)) + return Actor.result(TicketStore.get(self._args[1], invalidate=True, owner=SECURE_OWNER if secure else OWNER)) except Exception: return Actor.result({}) def getSecureTicket(self): + ''' + Processes get request for SECURE tickets request, i.e. tickets that can only be got by actors with valid credentials + GET /rest/actor/sticket/[ticketId]?key=[master key] + ''' logger.debug('Get secure ticket value for {}'.format(self._args)) - v = self.validateRequestKey() - if v is not None: - return v + # v = self.validateRequestKey() + # if v is not None: + # return v - return self.getTicket(secure=True) + # TODO: Remove this, is just for testings + # return Actor.result({'username': 'user', 'password': 'password', 'domain': None}) + # return self.getTicket(secure=True) + raise RequestError('Invalid request') def get(self): ''' @@ -156,7 +166,7 @@ class Actor(Handler): if self._args[0] == 'ticket': return self.getTicket() - if self._args[0] == 'secureTicket': + if self._args[0] == 'sticket': return self.getSecureTicket() if self._args[0] == 'testn': # Test, but without master key @@ -174,6 +184,7 @@ class Actor(Handler): actorVersion = self._params.get('version', 'unknown') service = self.getUserServiceByIds() if service is None: + logger.info('Unmanaged host request: {}'.format(self._args)) return Actor.result(_('Unmanaged host'), error=ERR_HOST_NOT_MANAGED) else: # Set last seen actor version @@ -212,6 +223,10 @@ class Actor(Handler): logger.debug('Setting comms url to {}'.format(data)) service.setCommsUrl(data) return Actor.result('ok') + elif message == 'ssoAvailable': + logger.debug('Setting that SSO is available') + service.setProperty('sso_available', 1) + return Actor.result('ok') elif message == 'version': version = self._params.get('version', 'unknown') logger.debug('Got notified version {}'.format(version)) diff --git a/server/src/uds/core/managers/CryptoManager.py b/server/src/uds/core/managers/CryptoManager.py index 4380de76..5e5fe237 100644 --- a/server/src/uds/core/managers/CryptoManager.py +++ b/server/src/uds/core/managers/CryptoManager.py @@ -36,6 +36,7 @@ from django.conf import settings from Crypto.PublicKey import RSA from OpenSSL import crypto from Crypto.Random import atfork + import hashlib import array import uuid @@ -58,6 +59,7 @@ logger = logging.getLogger(__name__) class CryptoManager(object): CODEC = 'base64' + INITIAL_VECTOR = 'UDS AES Initial.' instance = None diff --git a/server/src/uds/migrations/0022_ticketstore_owner.py b/server/src/uds/migrations/0022_ticketstore_owner.py new file mode 100644 index 00000000..6a0d576a --- /dev/null +++ b/server/src/uds/migrations/0022_ticketstore_owner.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.5 on 2016-06-15 09:24 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('uds', '0021_auto_20160405_0429'), + ] + + operations = [ + migrations.AddField( + model_name='ticketstore', + name='owner', + field=models.CharField(blank=True, default=None, max_length=8, null=True), + ), + ] diff --git a/server/src/uds/models/TicketStore.py b/server/src/uds/models/TicketStore.py index fcf12649..1e968242 100644 --- a/server/src/uds/models/TicketStore.py +++ b/server/src/uds/models/TicketStore.py @@ -45,7 +45,7 @@ import logging logger = logging.getLogger(__name__) -__updated__ = '2016-06-15' +__updated__ = '2016-06-17' class TicketStore(UUIDModel): @@ -57,6 +57,7 @@ class TicketStore(UUIDModel): MAX_VALIDITY = 60 * 60 * 12 # Cleanup will purge all elements that have been created MAX_VALIDITY ago + owner = models.CharField(null=True, blank=True, default=None, max_length=8) stamp = models.DateTimeField() # Date creation or validation of this entry validity = models.IntegerField(default=60) # Duration allowed for this ticket to be valid, in seconds @@ -78,46 +79,49 @@ class TicketStore(UUIDModel): @staticmethod def generateUuid(): - # more secure is this: + # more owner is this: # ''.join(random.SystemRandom().choice(string.ascii_lowercase + string.digits) for _ in range(40)) - return ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(40)) + return cryptoManager().randomString(40) @staticmethod - def create(data, validator=None, validity=DEFAULT_VALIDITY, secure=False): + def create(data, validator=None, validity=DEFAULT_VALIDITY, owner=None, secure=False): ''' validity is in seconds ''' if validator is not None: validator = pickle.dumps(validator) - uuid = TicketStore.objects.create(stamp=getSqlDatetime(), data=pickle.dumps(data), validator=validator, validity=validity).uuid - if secure is False: - return uuid - else: - return cryptoManager().encrypt(uuid)[:-2] + data = pickle.dumps(data) + if secure: + data = cryptoManager().encrypt(data) + + return TicketStore.objects.create(stamp=getSqlDatetime(), data=data, validator=validator, validity=validity, owner=owner).uuid @staticmethod - def store(uuid, data, validator=None, validity=DEFAULT_VALIDITY): + def store(uuid, data, validator=None, validity=DEFAULT_VALIDITY, owner=owner, secure=False): ''' Stores an ticketstore. If one with this uuid already exists, replaces it. Else, creates a new one validity is in seconds ''' if validator is not None: validator = pickle.dumps(validator) + + data = pickle.dumps(data) + if secure: + data = cryptoManager().encrypt() + try: - t = TicketStore.objects.get(uuid=uuid) - t.data = pickle.dumps(data) + t = TicketStore.objects.get(uuid=uuid, owner=owner) + t.data = data t.stamp = getSqlDatetime() t.validity = validity t.save() except TicketStore.DoesNotExist: - t = TicketStore.objects.create(uuid=uuid, stamp=getSqlDatetime(), data=pickle.dumps(data), validator=validator, validity=validity) + t = TicketStore.objects.create(uuid=uuid, stamp=getSqlDatetime(), data=data, validator=validator, validity=validity, owner=owner) @staticmethod - def get(uuid, invalidate=True, secure=False): - if secure: - uuid = cryptoManager().decrypt(uuid + "=\n") + def get(uuid, invalidate=True, owner=None, secure=False): try: - t = TicketStore.objects.get(uuid=uuid) + t = TicketStore.objects.get(uuid=uuid, owner=owner) validity = datetime.timedelta(seconds=t.validity) now = getSqlDatetime() @@ -125,7 +129,10 @@ class TicketStore(UUIDModel): if t.stamp + validity < now: raise TicketStore.InvalidTicket('Not valid anymore') - data = pickle.loads(t.data) + if secure is True: + data = pickle.loads(cryptoManager().decrypt(t.data)) + else: + data = pickle.loads(t.data) # If has validator, execute it if t.validator is not None: @@ -143,9 +150,9 @@ class TicketStore(UUIDModel): raise TicketStore.InvalidTicket('Does not exists') @staticmethod - def revalidate(uuid, validity=None): + def revalidate(uuid, validity=None, owner=None): try: - t = TicketStore.objects.get(uuid=uuid) + t = TicketStore.objects.get(uuid=uuid, owner=owner) t.stamp = getSqlDatetime() if validity is not None: t.validity = validity @@ -166,4 +173,4 @@ class TicketStore(UUIDModel): else: validator = None - return 'Ticket id: {}, Stamp: {}, Validity: {}, Validator: {}, Data: {}'.format(self.uuid, self.stamp, self.validity, validator, pickle.loads(self.data)) + return 'Ticket id: {}, Secure: {}, Stamp: {}, Validity: {}, Validator: {}, Data: {}'.format(self.uuid, self.owner, self.stamp, self.validity, validator, pickle.loads(self.data))