Started to implement a mechanism to allow a secure sso.

We have started a way for pass the credentials from UDS directly to
VM, without passing it to UDS.
  Currently we are working on a credential provider for windows, that
will interact with UDS. We will release this provider as soon as it is
functional ;-)
This commit is contained in:
Adolfo Gómez García 2016-06-17 12:15:07 +02:00
parent 2683fddfc1
commit 3f7fb77086
4 changed files with 71 additions and 27 deletions

View File

@ -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))

View File

@ -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

View File

@ -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),
),
]

View File

@ -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))