From ae0968f58f2c1fc0ad3ba7ea3ac0e3cf6517ed8f Mon Sep 17 00:00:00 2001 From: Marc Aymerich Date: Wed, 29 Jul 2015 09:05:07 +0000 Subject: [PATCH] Improved webapps directive validation --- TODO.md | 3 ++ orchestra/contrib/lists/serializers.py | 6 +-- orchestra/contrib/payments/serializers.py | 10 ++-- orchestra/contrib/resources/serializers.py | 6 +-- orchestra/contrib/systemusers/forms.py | 8 ++++ orchestra/contrib/systemusers/models.py | 1 + orchestra/contrib/systemusers/serializers.py | 24 +++++----- orchestra/contrib/systemusers/validators.py | 2 +- orchestra/contrib/websites/directives.py | 50 ++++++++------------ 9 files changed, 55 insertions(+), 55 deletions(-) diff --git a/TODO.md b/TODO.md index 5c4f68c5..a3c51160 100644 --- a/TODO.md +++ b/TODO.md @@ -426,3 +426,6 @@ Case # Discount prepaid metric should be more optimal https://orchestra.pangea.org/admin/orders/order/40/ # -> order.billed_metric besides billed_until + + +# websites directives: redirect strip() and allow empty URL_path diff --git a/orchestra/contrib/lists/serializers.py b/orchestra/contrib/lists/serializers.py index ad6f2381..be44f37b 100644 --- a/orchestra/contrib/lists/serializers.py +++ b/orchestra/contrib/lists/serializers.py @@ -34,13 +34,11 @@ class ListSerializer(AccountSerializerMixin, SetPasswordHyperlinkedSerializer): fields = ('url', 'id', 'name', 'password', 'address_name', 'address_domain', 'admin_email') postonly_fields = ('name', 'password') - def validate_address_domain(self, attrs, source): - address_domain = attrs.get(source) - address_name = attrs.get('address_name') + def validate_address_domain(self, address_name): if self.instance: address_domain = address_domain or self.instance.address_domain address_name = address_name or self.instance.address_name if address_name and not address_domain: raise serializers.ValidationError( _("address_domains should should be provided when providing an addres_name")) - return attrs + return address_name diff --git a/orchestra/contrib/payments/serializers.py b/orchestra/contrib/payments/serializers.py index b026e6c2..e423abbb 100644 --- a/orchestra/contrib/payments/serializers.py +++ b/orchestra/contrib/payments/serializers.py @@ -11,13 +11,15 @@ class PaymentSourceSerializer(AccountSerializerMixin, serializers.HyperlinkedMod model = PaymentSource fields = ('url', 'id', 'method', 'data', 'is_active') - def validate_data(self, attrs, source): - plugin = PaymentMethod.get(attrs['method']) + def validate(self, data): + """ validate data according to method """ + data = super(PaymentSourceSerializer, self).validate(data) + plugin = PaymentMethod.get(data['method']) serializer_class = plugin().get_serializer() - serializer = serializer_class(data=attrs[source]) + serializer = serializer_class(data=data['data']) if not serializer.is_valid(): raise serializers.ValidationError(serializer.errors) - return attrs + return data def transform_data(self, obj, value): if not obj: diff --git a/orchestra/contrib/resources/serializers.py b/orchestra/contrib/resources/serializers.py index fa21610c..0ffadf2f 100644 --- a/orchestra/contrib/resources/serializers.py +++ b/orchestra/contrib/resources/serializers.py @@ -48,9 +48,8 @@ def insert_resource_serializers(): except KeyError: continue # TODO this is a fucking workaround, reimplement this on the proper place - def validate_resources(self, attrs, source, _resources=resources): + def validate_resources(self, posted, _resources=resources): """ Creates missing resources """ - posted = attrs.get(source, []) result = [] resources = list(_resources) for data in posted: @@ -67,8 +66,7 @@ def insert_resource_serializers(): if not resource.on_demand: data.allocated = resource.default_allocation result.append(data) - attrs[source] = result - return attrs + return result viewset = router.get_viewset(model) viewset.serializer_class.validate_resources = validate_resources diff --git a/orchestra/contrib/systemusers/forms.py b/orchestra/contrib/systemusers/forms.py index 886f493f..dc30fbfd 100644 --- a/orchestra/contrib/systemusers/forms.py +++ b/orchestra/contrib/systemusers/forms.py @@ -62,6 +62,10 @@ class SystemUserFormMixin(object): };""" % username ) + def clean_directory(self): + directory = self.cleaned_data['directory'] + return directory.lstrip('/') + def clean(self): super(SystemUserFormMixin, self).clean() cleaned_data = self.cleaned_data @@ -113,6 +117,10 @@ class PermissionForm(forms.Form): (user.get_base_home(), user.get_base_home()) for user in related_users ) + def clean_home_extension(self): + home_extension = self.cleaned_data['home_extension'] + return home_extension.lstrip('/') + def clean(self): cleaned_data = super(PermissionForm, self).clean() path = os.path.join(cleaned_data['base_home'], cleaned_data['home_extension']) diff --git a/orchestra/contrib/systemusers/models.py b/orchestra/contrib/systemusers/models.py index 1b7c640f..62798d2c 100644 --- a/orchestra/contrib/systemusers/models.py +++ b/orchestra/contrib/systemusers/models.py @@ -96,6 +96,7 @@ class SystemUser(models.Model): super(SystemUser, self).save(*args, **kwargs) def clean(self): + self.directory = self.directory.lstrip('/') if self.home: self.home = os.path.normpath(self.home) if self.directory: diff --git a/orchestra/contrib/systemusers/serializers.py b/orchestra/contrib/systemusers/serializers.py index 05c64f51..e9cf1257 100644 --- a/orchestra/contrib/systemusers/serializers.py +++ b/orchestra/contrib/systemusers/serializers.py @@ -24,20 +24,20 @@ class SystemUserSerializer(AccountSerializerMixin, SetPasswordHyperlinkedSeriali ) postonly_fields = ('username', 'password') - def validate(self, attrs): - attrs = super(SystemUserSerializer, self).validate(attrs) - user = SystemUser( - username=attrs.get('username') or self.instance.username, - shell=attrs.get('shell') or self.instance.shell, - ) - validate_home(user, attrs, self.get_account()) - return attrs + def validate_directory(self, directory): + return directory.lstrip('/') - def validate_groups(self, attrs, source): - groups = attrs.get(source) + def validate(self, data): + data = super(SystemUserSerializer, self).validate(data) + user = SystemUser( + username=data.get('username') or self.instance.username, + shell=data.get('shell') or self.instance.shell, + ) + validate_home(user, data, self.get_account()) + groups = data.get('groups') if groups: for group in groups: - if group.username == attrs['username']: + if group.username == data['username']: raise serializers.ValidationError( _("Do not make the user member of its group")) - return attrs + return data diff --git a/orchestra/contrib/systemusers/validators.py b/orchestra/contrib/systemusers/validators.py index 3c5f0839..9dda0890 100644 --- a/orchestra/contrib/systemusers/validators.py +++ b/orchestra/contrib/systemusers/validators.py @@ -6,7 +6,7 @@ from django.utils.translation import ugettext_lazy as _ from orchestra.contrib.orchestration import Operation -def validate_path_exists(user, path, ): +def validate_path_exists(user, path): user.path_to_validate = path log = Operation.execute_action(user, 'validate_path_exists')[0] if 'path does not exists' in log.stderr: diff --git a/orchestra/contrib/websites/directives.py b/orchestra/contrib/websites/directives.py index 6038e210..65922d91 100644 --- a/orchestra/contrib/websites/directives.py +++ b/orchestra/contrib/websites/directives.py @@ -84,12 +84,13 @@ class SiteDirective(Plugin): if errors: raise ValidationError(errors) - def validate(self, website): - if self.regex and not re.match(self.regex, website.value): + def validate(self, directive): + directive.value = directive.value.strip() + if self.regex and not re.match(self.regex, directive.value): raise ValidationError({ 'value': ValidationError(_("'%(value)s' does not match %(regex)s."), params={ - 'value': website.value, + 'value': directive.value, 'regex': self.regex }), }) @@ -99,20 +100,25 @@ class Redirect(SiteDirective): name = 'redirect' verbose_name = _("Redirection") help_text = _("<website path> <destination URL>") - regex = r'^[^ ]+\s[^ ]+$' + regex = r'^[^ ]*\s[^ ]+$' group = SiteDirective.HTTPD unique_value = True unique_location = True + + def validate(self, directive): + """ inserts default url path if not provided """ + values = directive.value.strip().split() + if len(values) == 1: + values.insert(0, '/') + directive.value = ' '.join(values) + super(Redirect, self).validate(directive) -class Proxy(SiteDirective): +class Proxy(Redirect): name = 'proxy' verbose_name = _("Proxy") help_text = _("<website path> <target URL>") regex = r'^[^ ]+\shttp[^ ]+(timeout=[0-9]{1,3}|retry=[0-9]|\s)*$' - group = SiteDirective.HTTPD - unique_value = True - unique_location = True class ErrorDocument(SiteDirective): @@ -132,27 +138,21 @@ class SSLCA(SiteDirective): name = 'ssl-ca' verbose_name = _("SSL CA") help_text = _("Filesystem path of the CA certificate file.") - regex = r'^[^ ]+$' + regex = r'^/[^ ]+$' group = SiteDirective.SSL unique_name = True -class SSLCert(SiteDirective): +class SSLCert(SSLCA): name = 'ssl-cert' verbose_name = _("SSL cert") help_text = _("Filesystem path of the certificate file.") - regex = r'^[^ ]+$' - group = SiteDirective.SSL - unique_name = True -class SSLKey(SiteDirective): +class SSLKey(SSLCA): name = 'ssl-key' verbose_name = _("SSL key") help_text = _("Filesystem path of the key file.") - regex = r'^[^ ]+$' - group = SiteDirective.SSL - unique_name = True class SecRuleRemove(SiteDirective): @@ -164,13 +164,11 @@ class SecRuleRemove(SiteDirective): unique_location = True -class SecEngine(SiteDirective): +class SecEngine(SecRuleRemove): name = 'sec-engine' verbose_name = _("SecRuleEngine Off") help_text = _("URL path with disabled modsecurity engine.") regex = r'^/[^ ]*$' - group = SiteDirective.SEC - unique_value = True class WordPressSaaS(SiteDirective): @@ -183,21 +181,13 @@ class WordPressSaaS(SiteDirective): unique_location = True -class DokuWikiSaaS(SiteDirective): +class DokuWikiSaaS(WordPressSaaS): name = 'dokuwiki-saas' verbose_name = "DokuWiki SaaS" help_text = _("URL path for mounting wordpress multisite.") - group = SiteDirective.SAAS - regex = r'^/[^ ]*$' - unique_value = True - unique_location = True -class DrupalSaaS(SiteDirective): +class DrupalSaaS(WordPressSaaS): name = 'drupal-saas' verbose_name = "Drupdal SaaS" help_text = _("URL path for mounting wordpress multisite.") - group = SiteDirective.SAAS - regex = r'^/[^ ]*$' - unique_value = True - unique_location = True