def validatePublication(self): """ Ensures that, if this service has publications, that a publication is active raises an IvalidServiceException if check fails """ if self.activePublication() is None and self.service.getType().publicationType is not None: raise InvalidServiceException()
def validateTransport(self, transport): try: self.transports.get(id=transport.id) except: raise InvalidServiceException()
def ticketAuth(request, ticketId): ''' Used to authenticate an user via a ticket ''' ticket = Ticket(ticketId) logger.debug('Ticket: {}'.format(ticket)) try: try: # Extract ticket.data from ticket.data storage, and remove it if success username = ticket.data['username'] groups = ticket.data['groups'] auth = ticket.data['auth'] realname = ticket.data['realname'] servicePool = ticket.data['servicePool'] password = ticket.data['password'] transport = ticket.data['transport'] except: logger.error('Ticket stored is not valid') raise InvalidUserException() # Remove ticket ticket.delete() auth = Authenticator.objects.get(uuid=auth) # If user does not exists in DB, create it right now # Add user to groups, if they exists... grps = [] for g in groups: try: grps.append(auth.groups.get(uuid=g)) except Exception: logger.debug('Group list has changed since ticket assignement') if len(grps) == 0: logger.error('Ticket has no valid groups') raise Exception('Invalid ticket authentication') usr = auth.getOrCreateUser(username, realname) if usr is None or State.isActive( usr.state) is False: # If user is inactive, raise an exception raise InvalidUserException() # Add groups to user (replace existing groups) usr.groups = grps # Right now, we assume that user supports java, let's see how this works # Force cookie generation webLogin(request, None, usr, password) request.user = usr # Temporarily store this user as "authenticated" user, next requests will be done using session # Check if servicePool is part of the ticket if servicePool is not None: servicePool = DeployedService.objects.get(uuid=servicePool) # Check if service pool can't be accessed by groups servicePool.validateUser(usr) if servicePool.isInMaintenance(): raise ServiceInMaintenanceMode() transport = Transport.objects.get(uuid=transport) response = service( request, 'F' + servicePool.uuid, transport.uuid) # 'A' Indicates 'assigned service' else: response = HttpResponsePermanentRedirect( reverse('uds.web.views.index')) # Now ensure uds cookie is at response getUDSCookie(request, response, True) return response except Authenticator.DoesNotExist: logger.error('Ticket has an non existing authenticator') return errors.error(request, InvalidUserException()) except DeployedService.DoesNotExist: logger.error('Ticket has an invalid Service Pool') return errors.error(request, InvalidServiceException()) except Exception as e: logger.exception('Exception') return errors.exceptionView(request, e)
def getService(self, user, srcIp, idService, idTransport, doTest=True): """ Get service info from """ userService = self.locateUserService(user, idService, create=True) # Early log of "access try" so we can imagine what is going on userService.setConnectionSource(srcIp, 'unknown') if userService.isInMaintenance() is True: raise ServiceInMaintenanceMode() if userService.deployed_service.isAccessAllowed() is False: raise ServiceAccessDeniedByCalendar() if idTransport is None or idTransport == '': # Find a suitable transport for v in userService.deployed_service.transports.order_by( 'priority'): if v.validForIp(srcIp): idTransport = v.uuid break try: trans = Transport.objects.get(uuid=idTransport) except Exception: raise InvalidServiceException() # Ensures that the transport is allowed for this service if trans not in userService.deployed_service.transports.all(): raise InvalidServiceException() # If transport is not available for the request IP... if trans.validForIp(srcIp) is False: msg = 'The requested transport {} is not valid for {}'.format( trans.name, srcIp) logger.error(msg) raise InvalidServiceException(msg) if user is not None: userName = user.name else: userName = '******' if doTest is False: # traceLogger.info('GOT service "{}" for user "{}" with transport "{}" (NOT TESTED)'.format(userService.name, userName, trans.name)) return None, userService, None, trans, None serviceNotReadyCode = 0x0001 ip = 'unknown' # Test if the service is ready if userService.isReady(): serviceNotReadyCode = 0x0002 log.doLog( userService, log.INFO, "User {0} from {1} has initiated access".format( user.name, srcIp), log.WEB) # If ready, show transport for this service, if also ready ofc iads = userService.getInstance() ip = iads.getIp() userService.logIP(ip) # Update known ip if self.checkUuid( userService) is False: # Machine is not what is expected serviceNotReadyCode = 0x0004 log.doLog(userService, log.WARN, "User service is not accessible (ip {0})".format(ip), log.TRANSPORT) logger.debug( 'Transport is not ready for user service {0}'.format( userService)) else: events.addEvent(userService.deployed_service, events.ET_ACCESS, username=userName, srcip=srcIp, dstip=ip, uniqueid=userService.unique_id) if ip is not None: serviceNotReadyCode = 0x0003 itrans = trans.getInstance() if itrans.isAvailableFor(userService, ip): # userService.setConnectionSource(srcIp, 'unknown') log.doLog(userService, log.INFO, "User service ready", log.WEB) self.notifyPreconnect( userService, itrans.processedUser(userService, user), itrans.protocol) traceLogger.info( 'READY on service "{}" for user "{}" with transport "{}" (ip:{})' .format(userService.name, userName, trans.name, ip)) return ip, userService, iads, trans, itrans else: message = itrans.getCustomAvailableErrorMsg( userService, ip) log.doLog(userService, log.WARN, message, log.TRANSPORT) logger.debug( 'Transport is not ready for user service {}: {}'. format(userService, message)) else: logger.debug( 'Ip not available from user service {0}'.format( userService)) else: log.doLog( userService, log.WARN, "User {0} from {1} tried to access, but service was not ready". format(user.name, srcIp), log.WEB) traceLogger.error( 'ERROR {} on service "{}" for user "{}" with transport "{}" (ip:{})' .format(serviceNotReadyCode, userService.name, userName, trans.name, ip)) raise ServiceNotReadyError(code=serviceNotReadyCode, service=userService, transport=trans)
def ticketAuth(request, ticketId): """ Used to authenticate an user via a ticket """ try: data = TicketStore.get(ticketId, invalidate=True) try: # Extract ticket.data from ticket.data storage, and remove it if success username = data['username'] groups = data['groups'] auth = data['auth'] realname = data['realname'] servicePool = data['servicePool'] password = cryptoManager().decrypt(data['password']) transport = data['transport'] except Exception: logger.error('Ticket stored is not valid') raise InvalidUserException() auth = Authenticator.objects.get(uuid=auth) # If user does not exists in DB, create it right now # Add user to groups, if they exists... grps = [] for g in groups: try: grps.append(auth.groups.get(uuid=g)) except Exception: logger.debug('Group list has changed since ticket assignment') if len(grps) == 0: logger.error('Ticket has no valid groups') raise Exception('Invalid ticket authentication') usr = auth.getOrCreateUser(username, realname) if usr is None or State.isActive(usr.state) is False: # If user is inactive, raise an exception raise InvalidUserException() # Add groups to user (replace existing groups) usr.groups.set(grps) # Force cookie generation webLogin(request, None, usr, password) request.user = usr # Temporarily store this user as "authenticated" user, next requests will be done using session request.session['ticket'] = '1' # Store that user access is done using ticket logger.debug("Service & transport: {}, {}".format(servicePool, transport)) for v in DeployedService.objects.all(): logger.debug("{} {}".format(v.uuid, v.name)) # Check if servicePool is part of the ticket if servicePool is not None: # If service pool is in there, also is transport res = userServiceManager().getService(request.user, request.ip, 'F' + servicePool, transport, False) _x, userService, _x, transport, _x = res transportInstance = transport.getInstance() if transportInstance.ownLink is True: link = reverse('TransportOwnLink', args=('A' + userService.uuid, transport.uuid)) else: link = html.udsAccessLink(request, 'A' + userService.uuid, transport.uuid) response = render( request, theme.template('simpleLauncher.html'), { 'link': link } ) else: response = HttpResponsePermanentRedirect(reverse('uds.web.views.index')) # Now ensure uds cookie is at response getUDSCookie(request, response, True) return response except ServiceNotReadyError as e: return render( request, theme.template('service_not_ready.html'), { 'fromLauncher': True, 'code': e.code } ) except TicketStore.InvalidTicket: return render( request, theme.template('simpleLauncherAlreadyLaunched.html') ) except Authenticator.DoesNotExist: logger.error('Ticket has an non existing authenticator') return errors.exceptionView(request, InvalidUserException()) except DeployedService.DoesNotExist: logger.error('Ticket has an invalid Service Pool') return errors.exceptionView(request, InvalidServiceException()) except Exception as e: logger.exception('Exception') return errors.exceptionView(request, e)
def getMeta(self, user, srcIp, os, idMetaPool): logger.debug('This is meta') # We need to locate the service pool related to this meta, and also the transport # First, locate if there is a service in any pool associated with this metapool meta = MetaPool.objects.get(uuid=idMetaPool) # If access is denied by calendar... if meta.isAccessAllowed() is False: raise ServiceAccessDeniedByCalendar() # Sort pools based on meta selection if meta.policy == MetaPool.PRIORITY_POOL: pools = [(p.priority, p.pool) for p in meta.members.all()] elif meta.policy == MetaPool.MOST_AVAILABLE_BY_NUMBER: pools = [(p.usage(), p) for p in meta.pools.all()] else: pools = [(random.randint(0, 10000), p) for p in meta.pools.all()] # Sort pools related to policy now, and xtract only pools, not sort keys # Remove "full" pools (100%) from result and pools in maintenance mode, not ready pools, etc... pools = [ p[1] for p in sorted(pools, key=lambda x: x[0]) if p[1].usage() < 100 and p[1].isUsable() ] logger.debug('Pools: %s', pools) usable = None # Now, Lets find first if there is one assigned in ANY pool def ensureTransport(pool): usable = None for t in pool.transports.all().order_by('priority'): typeTrans = t.getType() if t.getType() and t.validForIp( srcIp) and typeTrans.supportsOs( os['OS']) and t.validForOs(os['OS']): usable = (pool, t) break return usable try: alreadyAssigned = UserService.objects.filter( deployed_service__in=pools, state__in=State.VALID_STATES, user=user, cache_level=0).order_by('deployed_service__name')[0] logger.debug('Already assigned %s', alreadyAssigned) # Ensure transport is available for the OS, and store it usable = ensureTransport(alreadyAssigned.deployed_service) # Found already assigned, ensure everythinf is fine if usable: self.getService(user, os, srcIp, 'F' + usable[0].uuid, usable[1].uuid, doTest=False) except Exception: # No service already assigned, lets find a suitable one for pool in pools: # Pools are already sorted, and "full" pools are filtered out # Ensure transport is available for the OS usable = ensureTransport(pool) # Stop if a pool-transport is found and can be assigned to user if usable: try: self.getService(user, os, srcIp, 'F' + usable[0].uuid, usable[1].uuid, doTest=False) break # If all goes fine, stop here except Exception as e: logger.info( 'Meta service {}:{} could not be assigned, trying a new one' .format(usable[0].name, e)) usable = None if not usable: log.doLog( meta, log.WARN, "No user service accessible from device (ip {}, os: {})". format(srcIp, os['OS']), log.SERVICE) raise InvalidServiceException( _('The service is not accessible from this device')) logger.debug('Found usable pair: %s', usable) usable[0].validateUser(user) # We have found an usable user service already assigned & can be accessed from this, so return it return None, usable[0], None, usable[1], None
def getAssignationForUser(self, ds, user): if ds.service.getInstance().spawnsNew is False: assignedUserService = self.getExistingAssignationForUser(ds, user) else: assignedUserService = None # If has an assigned user service, returns this without any more work if assignedUserService is not None: return assignedUserService if ds.isRestrained(): raise InvalidServiceException( _('The requested service is restrained')) # Now try to locate 1 from cache already "ready" (must be usable and at level 1) with transaction.atomic(): cache = ds.cachedUserServices().select_for_update().filter( cache_level=services.UserDeployment.L1_CACHE, state=State.USABLE, os_state=State.USABLE)[:1] if len(cache) != 0: cache = cache[0] # Ensure element is reserved correctly on DB if ds.cachedUserServices().select_for_update().filter( user=None, uuid=cache.uuid).update(user=user, cache_level=0) != 1: cache = None else: cache = None if cache == None: with transaction.atomic(): cache = ds.cachedUserServices().select_for_update().filter( cache_level=services.UserDeployment.L1_CACHE, state=State.USABLE)[:1] if len(cache) > 0: cache = cache[0] if ds.cachedUserServices().select_for_update().filter( user=None, uuid=cache.uuid).update( user=user, cache_level=0) != 1: cache = None else: cache = None if cache: cache.assignToUser(user, save=True) # Out of atomic transaction if cache is not None: logger.debug( 'Found a cached-ready service from {0} for user {1}, item {2}'. format(ds, user, cache)) events.addEvent(ds, events.ET_CACHE_HIT, fld1=ds.cachedUserServices().filter( cache_level=services.UserDeployment.L1_CACHE, state=State.USABLE).count()) return cache # Cache missed # Now find if there is a preparing one with transaction.atomic(): cache = ds.cachedUserServices().select_for_update().filter( cache_level=services.UserDeployment.L1_CACHE, state=State.PREPARING)[:1] if len(cache) > 0: cache = cache[0] if ds.cachedUserServices().select_for_update().filter( user=None, uuid=cache.uuid).update(user=user, cache_level=0) != 1: cache = None else: cache.assignToUser(user, save=True) else: cache = None # Out of atomic transaction if cache is not None: logger.debug( 'Found a cached-preparing service from {0} for user {1}, item {2}' .format(ds, user, cache)) events.addEvent(ds, events.ET_CACHE_MISS, fld1=ds.cachedUserServices().filter( cache_level=services.UserDeployment.L1_CACHE, state=State.PREPARING).count()) return cache # Can't assign directly from L2 cache... so we check if we can create e new service in the limits requested ty = ds.service.getType() if ty.usesCache is True: # inCacheL1 = ds.cachedUserServices().filter(UserServiceManager.getCacheStateFilter(services.UserDeployment.L1_CACHE)).count() inAssigned = ds.assignedUserServices().filter( UserServiceManager.getStateFilter()).count() # totalL1Assigned = inCacheL1 + inAssigned if inAssigned >= ds.max_srvs: # cacheUpdater will drop necesary L1 machines, so it's not neccesary to check against inCacheL1 log.doLog( ds, log.WARN, 'Max number of services reached: {}'.format(ds.max_srvs), log.INTERNAL) raise MaxServicesReachedError() # Can create new service, create it events.addEvent(ds, events.ET_CACHE_MISS, fld1=0) return self.createAssignedFor(ds, user)
def getService(request, idService, idTransport, doTest=True): kind, idService = idService[0], idService[1:] logger.debug('Kind of service: {0}, idService: {1}'.format( kind, idService)) if kind == 'A': # This is an assigned service logger.debug('Getting A service {}'.format(idService)) ads = UserService.objects.get(uuid=idService) ads.deployed_service.validateUser(request.user) else: ds = DeployedService.objects.get(uuid=idService) # We first do a sanity check for this, if the user has access to this service # If it fails, will raise an exception ds.validateUser(request.user) # Now we have to locate an instance of the service, so we can assign it to user. ads = UserServiceManager.manager().getAssignationForUser( ds, request.user) if ads.isInMaintenance() is True: raise ServiceInMaintenanceMode() logger.debug('Found service: {0}'.format(ads)) trans = Transport.objects.get(uuid=idTransport) # Ensures that the transport is allowed for this service if trans not in ads.deployed_service.transports.all(): raise InvalidServiceException() # If transport is not available for the request IP... if trans.validForIp(request.ip) is False: raise InvalidServiceException() if doTest is False: return (None, ads, None, trans, None) # Test if the service is ready if ads.isReady(): log.doLog( ads, log.INFO, "User {0} from {1} has initiated access".format( request.user.name, request.ip), log.WEB) # If ready, show transport for this service, if also ready ofc iads = ads.getInstance() ip = iads.getIp() events.addEvent(ads.deployed_service, events.ET_ACCESS, username=request.user.name, srcip=request.ip, dstip=ip, uniqueid=ads.unique_id) if ip is not None: itrans = trans.getInstance() if itrans.isAvailableFor(ip): ads.setConnectionSource(request.ip, 'unknown') log.doLog(ads, log.INFO, "User service ready", log.WEB) UserServiceManager.manager().notifyPreconnect( ads, itrans.processedUser(ads, request.user), itrans.protocol) return (ip, ads, iads, trans, itrans) else: log.doLog(ads, log.WARN, "User service is not accessible (ip {0})".format(ip), log.TRANSPORT) logger.debug( 'Transport is not ready for user service {0}'.format(ads)) else: logger.debug('Ip not available from user service {0}'.format(ads)) else: log.doLog( ads, log.WARN, "User {0} from {1} tried to access, but machine was not ready". format(request.user.name, request.ip), log.WEB) return None
def getService(self, user, srcIp, idService, idTransport, doTest=True): ''' Get service info from ''' kind, idService = idService[0], idService[1:] logger.debug('Kind of service: {0}, idService: {1}'.format( kind, idService)) if kind == 'A': # This is an assigned service logger.debug('Getting A service {}'.format(idService)) userService = UserService.objects.get(uuid=idService) userService.deployed_service.validateUser(user) else: ds = ServicePool.objects.get(uuid=idService) # We first do a sanity check for this, if the user has access to this service # If it fails, will raise an exception ds.validateUser(user) # Now we have to locate an instance of the service, so we can assign it to user. userService = self.getAssignationForUser(ds, user) logger.debug('Found service: {0}'.format(userService)) if userService.isInMaintenance() is True: raise ServiceInMaintenanceMode() # If service is not visible, do not allow it to be used if userService.deployed_service.isVisible() is False: raise InvalidServiceException() if userService.deployed_service.isAccessAllowed() is False: raise ServiceAccessDeniedByCalendar() if idTransport is None or idTransport == '': # Find a suitable transport for v in userService.deployed_service.transports.order_by( 'priority'): if v.validForIp(srcIp): idTransport = v.uuid break try: trans = Transport.objects.get(uuid=idTransport) except Exception: raise InvalidServiceException() # Ensures that the transport is allowed for this service if trans not in userService.deployed_service.transports.all(): raise InvalidServiceException() # If transport is not available for the request IP... if trans.validForIp(srcIp) is False: raise InvalidServiceException() if user is not None: userName = user.name if doTest is False: # traceLogger.info('GOT service "{}" for user "{}" with transport "{}" (NOT TESTED)'.format(userService.name, userName, trans.name)) return (None, userService, None, trans, None) serviceNotReadyCode = 0x0001 ip = 'unknown' # Test if the service is ready if userService.isReady(): serviceNotReadyCode = 0x0002 log.doLog( userService, log.INFO, "User {0} from {1} has initiated access".format( user.name, srcIp), log.WEB) # If ready, show transport for this service, if also ready ofc iads = userService.getInstance() ip = iads.getIp() if self.checkUuid( userService) is False: # Machine is not what is expected serviceNotReadyCode = 0x0004 log.doLog(userService, log.WARN, "User service is not accessible (ip {0})".format(ip), log.TRANSPORT) logger.debug( 'Transport is not ready for user service {0}'.format( userService)) else: events.addEvent(userService.deployed_service, events.ET_ACCESS, username=userName, srcip=srcIp, dstip=ip, uniqueid=userService.unique_id) if ip is not None: serviceNotReadyCode = 0x0003 itrans = trans.getInstance() if itrans.isAvailableFor(userService, ip): userService.setConnectionSource(srcIp, 'unknown') log.doLog(userService, log.INFO, "User service ready", log.WEB) self.notifyPreconnect( userService, itrans.processedUser(userService, user), itrans.protocol) traceLogger.info( 'READY on service "{}" for user "{}" with transport "{}" (ip:{})' .format(userService.name, userName, trans.name, ip)) return (ip, userService, iads, trans, itrans) else: log.doLog( userService, log.WARN, "User service is not accessible (ip {0})".format( ip), log.TRANSPORT) logger.debug( 'Transport is not ready for user service {0}'. format(userService)) else: logger.debug( 'Ip not available from user service {0}'.format( userService)) else: log.doLog( userService, log.WARN, "User {0} from {1} tried to access, but service was not ready". format(user.name, srcIp), log.WEB) traceLogger.error( 'ERROR {} on service "{}" for user "{}" with transport "{}" (ip:{})' .format(serviceNotReadyCode, userService.name, userName, trans.name, ip)) raise ServiceNotReadyError(code=serviceNotReadyCode, service=userService, transport=trans)