예제 #1
0
 def get_create_options(self, client, region_name, show_in_fleio=None, requested_image=None, requested_volume=None,
                        include_community_images=False, include_shared_images=False, is_staff=True):
     return super(StaffInstanceViewSet, self).get_create_options(
         client=client,
         region_name=region_name,
         show_in_fleio=show_in_fleio,
         requested_image=requested_image,
         requested_volume=requested_volume,
         include_community_images=staff_active_features.is_enabled('openstack.images.showcommunity'),
         include_shared_images=staff_active_features.is_enabled('openstack.images.showshared'),
         is_staff=is_staff,
     )
예제 #2
0
 def allowed(self):
     allowed = copy.deepcopy(INSTANCE_ALLOWED_ACTIONS)
     if staff_active_features.is_enabled('openstack.floatingips'):
         allowed[InstanceStatus.ACTIVE] += ['associate_ip', 'dissociate_ip']
         allowed[InstanceStatus.STOPPED] += [
             'associate_ip', 'dissociate_ip'
         ]
     if staff_active_features.is_enabled(
             'openstack.instances.allow_changing_password'):
         allowed[InstanceStatus.ACTIVE] += [
             'change_password',
         ]
     return allowed
예제 #3
0
    def destroy(self, request, pk=None):
        """Delete an OpenStack user"""

        if staff_active_features.is_enabled('demo'):
            raise ForbiddenException(
                detail=_('Operation not allowed in demo mode'))

        try:
            project_ids = [
                project.project_id for project in self.projects_queryset()
            ]

            os_user = self.os_user_api.get_user(user=pk)
            if getattr(os_user, 'default_project_id', None) not in project_ids:
                LOG.error(
                    'Could not delete user with id {pk}, because project {project} not found in database.'
                    .format(pk=pk, project=os_user.default_project_id))
                raise ValidationError({
                    'detail':
                    _('Unable to delete the user from OpenStack. Check logs for more info'
                      )
                })

            self.os_user_api.delete_user(user=pk)
        except (ClientException, IndexError) as e:
            LOG.error('Could not delete user with id {pk}, reason: {0}'.format(
                e, pk=pk))
            raise ValidationError({
                'detail':
                _('Unable to delete the user from OpenStack. Check logs for more info'
                  )
            })
        else:
            return Response({'detail': _('User deleted')},
                            status=HTTP_204_NO_CONTENT)
예제 #4
0
 def get_queryset(self):
     if not staff_active_features.is_enabled('openstack.instances.traffic'):
         traffic_resource = BillingResource.objects.filter(name='instance_traffic').first()
         queryset = self.queryset.exclude(resource=traffic_resource).all()
         return queryset
     else:
         return self.queryset
예제 #5
0
def get_services_statuses(request):
    celery_active = False
    if getattr(settings, 'CELERY_TASK_ALWAYS_EAGER', False) is True:
        celery_active = True
    else:
        celery_workers = celery.control.inspect().active(
        )  # gets celery workers
        celery_workers_list = celery_workers.keys() if celery_workers else None
        if celery_workers_list and len(celery_workers_list) > 0:
            celery_active = True

    response_dict = OrderedDict([
        ('celery', celery_active),
    ])

    # check updated status
    if staff_active_features.is_enabled('openstack'):
        with open(
                getattr(settings, 'UPDATED_LOCK_FILE',
                        '/var/fleio/updated_lock.pid'), 'a+') as fp:
            try:
                fcntl.flock(fp.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
            except IOError:
                # file is locked, updated is running
                updated = True
            else:
                # file is not locked, updated is not running
                fcntl.flock(fp.fileno(), fcntl.F_UNLCK)
                updated = False
        response_dict['updated'] = updated
    return Response(response_dict)
예제 #6
0
def check_sfa_required_and_get_settings(
        user: AppUser) -> (bool, Optional[Response]):
    if user.is_staff:
        if not staff_active_features.is_enabled(
                'clients&users.second_factor_auth'):
            return False, None
    else:
        if not active_features.is_enabled('clients&users.second_factor_auth'):
            return False, None
    sfa_methods = SecondFactorAuthMethod.objects.filter(user=user,
                                                        enabled=True)
    enabled_sfa_methods = sfa_methods.count()
    if enabled_sfa_methods:
        # if user has sfa methods enabled, sfa is required and he'll be able to choose from one of those
        available_sfa_methods = list()
        for method in sfa_methods:
            available_sfa_methods.append(
                dict(
                    name=method.type.name,
                    display_name=method.type.display_name,
                    default=method.default,
                    help_text=method.type.help_text,
                ))
        return True, Response({
            'detail':
            _('Second factor authentication required'),
            'sfa_required':
            True,
            'sfa_methods':
            available_sfa_methods,
        })
    return False, None
예제 #7
0
 def perform_destroy(self, instance: AppUser):
     if (instance.is_superuser or instance.username
             == 'demo') and staff_active_features.is_enabled('demo'):
         # don't allow deletion of superuser or enduser demo account in demo mode
         raise ForbiddenException(
             detail=_('Operation not allowed in demo mode'))
     if instance.is_superuser:
         if self.request.user.username == instance.username or self.request.user.is_superuser is False:
             raise PermissionDenied
     pk = instance.id
     if instance.username == self.request.user.username:
         raise APIBadRequest(
             _('Cannot delete the user you are logged in with.'))
     with transaction.atomic():
         if instance.permissions:
             instance.permissions.delete()
         instance.delete()
         user = self.request.user
         staff_delete_user.send(sender=__name__,
                                user=user,
                                user_id=user.id,
                                deleted_user_name=instance.username,
                                deleted_user_id=pk,
                                username=user.username,
                                request=self.request)
예제 #8
0
 def get_selected_volume(project, volume):
     if staff_active_features.is_enabled('openstack.images.shareoncreate'):
         try:
             models.Volume.objects.get(pk=volume.pk)
         except (models.Volume.DoesNotExist, models.Volume.MultipleObjectsReturned):
             raise exceptions.APIBadRequest(detail=_('Volume not found'), code=404)
     return StaffInstanceViewSet.get_selected_volume(project, volume)
예제 #9
0
    def dissociate_user(self, request, pk):
        del pk  # unused
        if staff_active_features.is_enabled('demo'):
            raise ForbiddenException(
                detail=_('Operation not allowed in demo mode'))

        client = self.get_object()
        try:
            # delete the cart related to client
            client_cart = client.fleio_cart
            client_cart.delete()
        except Client.fleio_cart.RelatedObjectDoesNotExist:
            pass
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user_model = get_user_model()
        try:
            user = user_model.objects.get(
                id=serializer.validated_data['user_id'])
            try:
                # delete the cart related to user
                user_cart = user.fleio_cart
                user_cart.delete()
            except user_model.fleio_cart.RelatedObjectDoesNotExist:
                pass
        except user_model.DoesNotExist:
            raise ObjectNotFound({'detail': _('User not found')})
        UserToClient.objects.filter(user=user, client=client).delete()
        return Response({'detail': _('User dissociated')})
예제 #10
0
    def refresh_plugins(self):
        definitions = {}  # type: Dict[str, PluginDefinition]
        for app_config in apps.apps.get_app_configs():  # type: apps.AppConfig
            if hasattr(app_config, 'initialize_plugin') and callable(
                    app_config.initialize_plugin):
                LOG.info('Found plugin {}'.format(app_config.name))
                definition = app_config.initialize_plugin(
                )  # type: PluginDefinition
                definition.refresh_components()
                definitions[definition.app_label] = definition

        self.found_plugin_definitions = dict(definitions)

        plugins_in_db = []

        # update database
        for plugin in Plugin.objects.all():
            if plugin.app_label in definitions:
                plugins_in_db.append(plugin.app_label)

                if not plugin.app_loaded:
                    plugin.app_loaded = True
                    plugin.save(update_fields=['app_loaded'])

                # remove disabled definitions
                if not plugin.enabled:
                    del definitions[plugin.app_label]
                else:
                    definitions[plugin.app_label].plugin_model = plugin
            else:
                if plugin.app_loaded:
                    plugin.app_loaded = False
                    plugin.save(update_fields=['app_loaded'])

        for app_label in definitions:
            if app_label not in plugins_in_db:
                plugin_definition = definitions[
                    app_label]  # type: PluginDefinition
                plugin_definition.plugin_model = Plugin.objects.create(
                    display_name=plugin_definition.display_name,
                    app_name=plugin_definition.app_name,
                    app_label=plugin_definition.app_label,
                    feature_name=plugin_definition.feature_name,
                    staff_feature_name=plugin_definition.staff_feature_name,
                    app_loaded=True)

        for definition in definitions.values():
            if active_features.is_enabled(definition.feature_name):
                LOG.info('Plugin {} is enabled for enduser'.format(
                    definition.app_label))
                self.enduser_active_plugin_definitions[
                    definition.app_label] = definition
            if staff_active_features.is_enabled(definition.staff_feature_name):
                LOG.info('Plugin {} is enabled for staff'.format(
                    definition.app_label))
                self.staff_active_plugin_definitions[
                    definition.app_label] = definition

        self.active_plugin_definitions = definitions
예제 #11
0
 def get_queryset(self):
     if self.action == 'list':
         qs = NotificationTemplate.objects.filter(
             language=getattr(settings, 'DEFAULT_NOTIFICATION_TEMPLATE_LANGUAGE_CODE'))
     else:
         qs = NotificationTemplate.objects.all()
     if not staff_active_features.is_enabled('openstack'):
         qs = qs.exclude(category__name='openstack')
     return qs
예제 #12
0
 def get_selected_image(project, image):
     """Validate and serialize selected image for create options"""
     if staff_active_features.is_enabled('openstack.images.shareoncreate'):
         try:
             models.Image.objects.get(pk=image.pk)
         except (models.Image.DoesNotExist, models.Image.MultipleObjectsReturned):
             raise exceptions.APIBadRequest(detail=_('Image not found'), code=404)
         return images_serializers.ImageSerializer(initial=image).to_representation(image)
     else:
         StaffInstanceViewSet.get_selected_image(project, image)
예제 #13
0
 def perform_create(self, serializer):
     serializer.is_valid(raise_exception=True)
     new_user_is_superuser = serializer.validated_data.get('is_superuser')
     if new_user_is_superuser and staff_active_features.is_enabled('demo'):
         # don't allow creation of superusers in demo mode
         raise ForbiddenException(
             detail=_('Operation not allowed in demo mode'))
     # Don't allow users to create super users
     if new_user_is_superuser is True and self.request.user.is_superuser is False:
         raise PermissionDenied
     serializer.save()
예제 #14
0
 def get_instance_backups_and_backup_schedules(self, request, id):
     if not staff_active_features.is_enabled('openstack.osbackup'):
         raise APIBadRequest(_('Backup feature is disabled.'))
     del request  # unused
     instance = self.get_instance()
     backup_schedules_qs = OpenStackBackupSchedule.objects.filter(instance__id=instance.uuid)
     backups = models.Image.objects.filter(type='backup', instance_uuid=instance.uuid)
     return Response({
         'schedules': BackupScheduleSerializer(instance=backup_schedules_qs, many=True).data,
         'backups': images_serializers.ImageBriefSerializer(instance=backups, many=True).data,
     })
예제 #15
0
    def handle(self, *args, **options):
        if len(sys.argv) > 1 and sys.argv[1] in ['update_frontend']:
            del sys.argv[1]

        if staff_active_features.is_enabled('demo'):
            self.stdout.write('Frontend cannot be updated in demo mode!')
            return

        self.stdout.write('Updating frontend ...')
        index_manager = IndexManager()
        index_manager.update_frontend()
        self.stdout.write('Fronted updated.')
예제 #16
0
def get_app_status(request):
    if staff_active_features.is_enabled('openstack'):
        updated_info = AppStatus.objects.filter(
            status_type=StatusTypesMap.updated_messages_count).first()
    else:
        updated_info = None
    if updated_info:
        return Response({
            'updated_info_details': updated_info.details_as_dict,
            'updated_info_last_updated': updated_info.last_updated,
        })
    return Response(dict())
예제 #17
0
    def update(self, request, pk):
        serializer_context = {'request': request}
        serializer = StaffUpdateUserProfileSerializer(
            data=request.data, context=serializer_context)
        serializer.is_valid(raise_exception=True)
        user = request.user  # type: AppUser
        updated_user_fields = utils.get_user_changed_values(
            user, serializer.validated_data)
        log_text = utils.format_for_log(updated_user_fields)
        password = serializer.validated_data.get('password', None)
        old_password = serializer.validated_data.get('old_password', None)
        user.first_name = serializer.validated_data['first_name']
        user.last_name = serializer.validated_data['last_name']
        user.email = serializer.validated_data['email']
        language = serializer.validated_data.get('language')
        if language:
            user.language = language
        if 'mobile_phone_number' in serializer.validated_data:
            user.mobile_phone_number = serializer.validated_data.get(
                'mobile_phone_number')

        self.allowed_to_update(user)

        password_changed = False
        if password and not staff_active_features.is_enabled('demo'):
            if user.check_password(old_password):
                user.set_password(password)
                utils.login_without_password(request, user)
                password_changed = True
            else:
                raise APIBadRequest(
                    _('Please enter the correct current password.'))

        user.save()

        if password_changed:
            user_update_password.send(sender=__name__,
                                      user=user,
                                      username=user.username,
                                      user_id=user.pk,
                                      email=user.email,
                                      request=request)
        if updated_user_fields:
            user_update.send(sender=__name__,
                             user=user,
                             username=user.username,
                             user_id=user.pk,
                             email=user.email,
                             request=request,
                             updated_data=log_text)

        return Response({'detail': _('User profile updated')})
예제 #18
0
    def update_frontend(self, request, *args, **kwargs):
        if staff_active_features.is_enabled('demo'):
            raise ForbiddenException(
                detail=_('Operation not allowed in demo mode'))

        del request, args, kwargs  # unused

        try:
            index_manager = IndexManager()
            index_manager.update_frontend()
        except IndexManager.IndexUpdateException as e:
            raise APIBadRequest(detail=e.detail)

        return Response()
예제 #19
0
    def handle(self, *args, **options):
        if options['type'] == 'staff':
            sys.exit(0 if staff_active_features.is_enabled(options['feature']
                                                           ) else 1)

        if options['type'] == 'reseller':
            sys.exit(0 if reseller_active_features.
                     is_enabled(options['feature']) else 1)

        if options['type'] == 'enduser':
            sys.exit(
                0 if active_features.is_enabled(options['feature']) else 1)

        sys.exit(1)
예제 #20
0
 def validate(self, attrs):
     attrs = super(StaffImageCreateSerializer, self).validate(attrs)
     if attrs.get(
             'source') == 'file' and not staff_active_features.is_enabled(
                 'openstack.images.file_uploads'):
         raise serializers.ValidationError(
             detail={'source': 'File uploads are not allowed.'})
     if attrs.get('source') == 'file' and not attrs.get('file'):
         raise serializers.ValidationError(
             detail={'source': 'A File is required'})
     elif attrs.get('source') == 'url' and not attrs.get('url'):
         raise serializers.ValidationError(
             detail={'url': 'A valid URL is required'})
     return attrs
예제 #21
0
def sign_up_settings_view(request):
    conf = SignUpSettingsConfig(raise_if_required_not_set=False)
    if request.method == 'GET':
        return get_sign_up_settings(configuration=conf,
                                    with_email_templates=True)
    elif request.method == 'POST':
        if staff_active_features.is_enabled('demo'):
            raise APIBadRequest(
                _('Cannot change sign up settings in demo mode'))
        serializer = SignUpSettingsSerializer(instance=conf, data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return get_sign_up_settings(configuration=conf)
    else:
        return Response({})
예제 #22
0
 def update_billing_plan(self, request, pk):
     del pk  # unused
     if not staff_active_features.is_enabled('openstack.plans'):
         raise APIBadRequest(detail=_('Cannot update os plan because openstack plans feature is disabled'))
     service = self.get_object()  # type: Service
     if service.status in [
         ServiceStatus.terminated,
         ServiceStatus.canceled,
         ServiceStatus.fraud
     ]:
         raise APIBadRequest(_('Cannot change pricing plan for service in this state.'))
     new_plan_id = request.data.get('plan')
     billing_module = module_factory.get_module_instance(service=service)
     billing_module.change_pricing_plan(service=service, new_plan_id=new_plan_id)
     return Response({'detail': _('Pricing plan updated')})
예제 #23
0
def send_staff_notification(name: str,
                            priority: str = Notification.PRIORITY_LOW,
                            variables: Optional[Dict[str, str]] = None):
    if not staff_active_features.is_enabled('notifications.send'):
        LOG.info('Notification sending is disabled for staff, aborting')
        return

    if variables is None:
        variables = {}
    for staff_user in AppUser.objects.filter(is_staff=True):
        send(
            name=name,
            priority=priority,
            user=staff_user,
            variables=variables,
        )
예제 #24
0
    def perform_destroy(self, db_image):
        """Delete the image."""
        if staff_active_features.is_enabled('demo'):
            raise ForbiddenException(detail=_('Operation not allowed in demo mode'))

        img = self.get_image()
        if img.db_image.protected:
            raise APIConflict(_("Can't delete protected image"))
        try:
            img.delete()
            user = self.request.user
            staff_delete_image.send(sender=__name__, user=user, user_id=user.id,
                                    image_name=img.db_image.name, image_id=img.db_image.id,
                                    username=user.username, request=self.request)
        except Exception as e:
            LOG.error("Cannot delete image, reason: {}".format(repr(e)))
            handle(self.request)
예제 #25
0
    def delete_project(self, request, pk):
        del pk  # unused

        if staff_active_features.is_enabled('demo'):
            raise ForbiddenException(
                detail=_('Operation not allowed in demo mode'))

        delete_all_resources = request.data.get('delete_all_resources', False)
        instance = self.get_object()
        if delete_all_resources:
            tasks.delete_client_project_resources.delay(
                project_id=instance.project_id, mark_project_as_deleted=False)
            return Response(status=200,
                            data={'details': _('Project delete scheduled')})
        else:
            project = OpenstackProject.with_admin_session(instance.project_id)
            project.delete()
            return Response(status=200, data={'details': _('Project deleted')})
예제 #26
0
def confirm_login(user, remember=False, **args) -> Optional[str]:
    """Method called when user supplies second factor authentication info on login
    Returns either the remember token or None, in either case the user will get logged in
    Raising exception denies access to user"""
    if user.is_staff:
        demo_mode = staff_active_features.is_enabled('demo')
    else:
        demo_mode = active_features.is_enabled('demo')
    if demo_mode:
        return None  # in demo mode, allow any input and sign in the user

    code = args.get('code')
    if not code:
        raise APIBadRequest(_('Confirmation code is missing'))
    try:
        int(code)
    except Exception as e:
        del e  # unused
        raise APIBadRequest(_('Code has to be a number'))
    if int(code) > 999999:
        raise APIBadRequest(_('Code has to be a 6 digit number'))
    sfa_type = SecondFactorAuthType.objects.filter(name=utils_get_app_name(
        app_name=SMSAuthenticatorPluginConfig.name)).first()
    if not sfa_type:
        raise SFATypeNotFound()
    sfa_method = SecondFactorAuthMethod.objects.filter(user=user,
                                                       type=sfa_type).first()
    if not sfa_method:
        raise SFAMethodNotAdded()
    sms_auth_data = SMSAuthenticatorData.objects.filter(
        method=sfa_method).first()
    secret_key = sms_auth_data.get_secret_key()
    result = pyotp.hotp.HOTP(secret_key).verify(otp=code,
                                                counter=sms_auth_data.counter)
    if result:
        sms_auth_data.counter = sms_auth_data.counter + 1
        sms_auth_data.save(update_fields=['counter'])
        if remember:
            return RememberSfa(user=user).make_token()
        return None
    else:
        raise APIBadRequest(_('Code is invalid'))
예제 #27
0
    def download(self, request, pk):
        del pk, request  # unused

        if not staff_active_features.is_enabled('openstack.images.download'):
            raise ForbiddenException(_('Image download not allowed'))

        db_image = self.get_object()  # type: OpenstackImage
        try:
            images_api = Images(api_session=self.os_admin_api.session)
            image_data = images_api.download(image=db_image)
        except (Exception, HTTPNotFound) as e:
            if type(e) == HTTPNotFound:
                raise ObjectNotFound(detail=e.details)
            LOG.exception(e)
            handle(self.request)
        else:
            response = StreamingHttpResponse(streaming_content=image_data)
            response['Content-Type'] = 'application/octet-stream'
            response['Content-Disposition'] = 'attachment; filename="{}"'.format(db_image.name)
            return response
예제 #28
0
    def save_custom_code(self, request, *args, **kwargs):
        if staff_active_features.is_enabled('demo'):
            raise ForbiddenException(
                detail=_('Operation not allowed in demo mode'))

        del args, kwargs  # unused

        custom_code = request.data.get('custom_code', None)
        if custom_code:
            for insertion_point in custom_code:
                custom_code_id = custom_code[insertion_point]['data'].get(
                    'id', None)
                instance = CustomCode.objects.filter(
                    id=custom_code_id).first() if custom_code_id else None
                serializer = CustomCodeSerializer(
                    data=custom_code[insertion_point]['data'],
                    instance=instance)
                if serializer.is_valid(raise_exception=True):
                    serializer.save()

        return Response()
예제 #29
0
    def perform_destroy(self, db_flavor):
        """Delete flavor from nova and mark as deleted in Fleio db."""
        if staff_active_features.is_enabled('demo'):
            raise ForbiddenException(
                detail=_('Operation not allowed in demo mode'))

        flavor_api = Flavors(api_session=self.identity_admin_api.session)
        flavor = flavor_api.get(flavor=db_flavor)
        try:
            pk = db_flavor.id
            flavor.delete()
            user = self.request.user
            staff_delete_flavor.send(sender=__name__,
                                     user=user,
                                     user_id=user.id,
                                     flavor_name=db_flavor.name,
                                     flavor_id=pk,
                                     username=user.username,
                                     request=self.request)
        except Exception as e:
            LOG.error(e)
            handle(self.request, message=e)
예제 #30
0
    def update_frontend(self):
        if staff_active_features.is_enabled('demo'):
            raise ForbiddenException(
                detail=_('Operation not allowed in demo mode'))

        if not self.is_local_frontend():
            raise IndexManager.IndexUpdateException(
                detail=_('Cannot find frontend instalation'))

        self.update_vanilla_indexes()

        if not self.has_vanilla_indexes():
            raise IndexManager.IndexUpdateException(
                detail=_('No unmodified index.html file available'))

        self.generate_updates_indexes()

        if not self.has_updated_indexes():
            raise IndexManager.IndexUpdateException(
                detail=_('Failed to generate updated index.html file'))

        self.update_local_frontend()