mirror of
https://github.com/ansible/awx.git
synced 2026-05-09 02:17:37 -02:30
AC-637 Credential now requires scm_key_unlock when saving encrypted ssh_key_data.
This commit is contained in:
@@ -10,6 +10,7 @@ import yaml
|
||||
|
||||
# Django
|
||||
from django.db import models
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.timezone import now
|
||||
|
||||
@@ -22,7 +23,7 @@ from taggit.managers import TaggableManager
|
||||
# Django-Celery
|
||||
from djcelery.models import TaskMeta
|
||||
|
||||
__all__ = ['VarsDictProperty', 'PrimordialModel', 'CommonModel',
|
||||
__all__ = ['VarsDictProperty', 'BaseModel', 'PrimordialModel', 'CommonModel',
|
||||
'CommonModelNameNotUnique', 'CommonTask', 'PERM_INVENTORY_ADMIN',
|
||||
'PERM_INVENTORY_READ', 'PERM_INVENTORY_WRITE',
|
||||
'PERM_INVENTORY_DEPLOY', 'PERM_INVENTORY_CHECK', 'JOB_TYPE_CHOICES',
|
||||
@@ -97,7 +98,56 @@ class VarsDictProperty(object):
|
||||
raise AttributeError('readonly property')
|
||||
|
||||
|
||||
class PrimordialModel(models.Model):
|
||||
class BaseModel(models.Model):
|
||||
'''
|
||||
Base model class with common methods for all models.
|
||||
'''
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
def __unicode__(self):
|
||||
if hasattr(self, 'name'):
|
||||
return u'%s-%s' % (self.name, self.id)
|
||||
else:
|
||||
return u'%s-%s' % (self._meta.verbose_name, self.id)
|
||||
|
||||
def clean_fields(self, exclude=None):
|
||||
'''
|
||||
Override default clean_fields to support methods for cleaning
|
||||
individual model fields.
|
||||
'''
|
||||
exclude = exclude or []
|
||||
errors = {}
|
||||
try:
|
||||
super(BaseModel, self).clean_fields(exclude)
|
||||
except ValidationError, e:
|
||||
errors = e.update_error_dict(errors)
|
||||
for f in self._meta.fields:
|
||||
if f.name in exclude:
|
||||
continue
|
||||
if hasattr(self, 'clean_%s' % f.name):
|
||||
try:
|
||||
setattr(self, f.attname,
|
||||
getattr(self, 'clean_%s' % f.name)())
|
||||
except ValidationError, e:
|
||||
errors[f.name] = e.messages
|
||||
if errors:
|
||||
raise ValidationError(errors)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
# For compatibility with Django 1.4.x, attempt to handle any calls to
|
||||
# save that pass update_fields.
|
||||
try:
|
||||
super(BaseModel, self).save(*args, **kwargs)
|
||||
except TypeError:
|
||||
if 'update_fields' not in kwargs:
|
||||
raise
|
||||
kwargs.pop('update_fields')
|
||||
super(BaseModel, self).save(*args, **kwargs)
|
||||
|
||||
|
||||
class PrimordialModel(BaseModel):
|
||||
'''
|
||||
common model for all object types that have these standard fields
|
||||
must use a subclass CommonModel or CommonModelNameNotUnique though
|
||||
@@ -136,27 +186,11 @@ class PrimordialModel(models.Model):
|
||||
)
|
||||
active = models.BooleanField(
|
||||
default=True,
|
||||
editable=False,
|
||||
)
|
||||
|
||||
tags = TaggableManager(blank=True)
|
||||
|
||||
def __unicode__(self):
|
||||
if hasattr(self, 'name'):
|
||||
return u'%s-%s' % (self.name, self.id)
|
||||
else:
|
||||
return u'%s-%s' % (self._meta.verbose_name, self.id)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
# For compatibility with Django 1.4.x, attempt to handle any calls to
|
||||
# save that pass update_fields.
|
||||
try:
|
||||
super(PrimordialModel, self).save(*args, **kwargs)
|
||||
except TypeError:
|
||||
if 'update_fields' not in kwargs:
|
||||
raise
|
||||
kwargs.pop('update_fields')
|
||||
super(PrimordialModel, self).save(*args, **kwargs)
|
||||
|
||||
def mark_inactive(self, save=True):
|
||||
'''Use instead of delete to rename and mark inactive.'''
|
||||
if self.active:
|
||||
@@ -166,6 +200,10 @@ class PrimordialModel(models.Model):
|
||||
if save:
|
||||
self.save()
|
||||
|
||||
def clean_description(self):
|
||||
# Description should always be empty string, never null.
|
||||
return self.description or ''
|
||||
|
||||
|
||||
class CommonModel(PrimordialModel):
|
||||
''' a base model where the name is unique '''
|
||||
|
||||
@@ -303,7 +303,7 @@ class Job(CommonTask):
|
||||
return self._get_hosts(job_host_summaries__processed__gt=0)
|
||||
|
||||
|
||||
class JobHostSummary(models.Model):
|
||||
class JobHostSummary(BaseModel):
|
||||
'''
|
||||
Per-host statistics for each job.
|
||||
'''
|
||||
@@ -367,7 +367,7 @@ class JobHostSummary(models.Model):
|
||||
self.host.save(update_fields=update_fields)
|
||||
self.host.update_computed_fields()
|
||||
|
||||
class JobEvent(models.Model):
|
||||
class JobEvent(BaseModel):
|
||||
'''
|
||||
An event/message logged from the callback when running a job.
|
||||
'''
|
||||
|
||||
@@ -254,6 +254,16 @@ class Credential(CommonModelNameNotUnique):
|
||||
def get_absolute_url(self):
|
||||
return reverse('api:credential_detail', args=(self.pk,))
|
||||
|
||||
def clean_ssh_key_unlock(self):
|
||||
if self.pk:
|
||||
ssh_key_data = decrypt_field(self, 'ssh_key_data')
|
||||
else:
|
||||
ssh_key_data = self.ssh_key_data
|
||||
if 'ENCRYPTED' in ssh_key_data and not self.ssh_key_unlock:
|
||||
raise ValidationError('SSH key unlock must be set when SSH key '
|
||||
'data is encrypted')
|
||||
return self.ssh_key_unlock
|
||||
|
||||
def clean(self):
|
||||
if self.user and self.team:
|
||||
raise ValidationError('Credential cannot be assigned to both a user and team')
|
||||
@@ -343,7 +353,7 @@ class Credential(CommonModelNameNotUnique):
|
||||
update_fields.append(field)
|
||||
self.save(update_fields=update_fields)
|
||||
|
||||
class Profile(models.Model):
|
||||
class Profile(BaseModel):
|
||||
'''
|
||||
Profile model related to User object. Currently stores LDAP DN for users
|
||||
loaded from LDAP.
|
||||
@@ -368,7 +378,7 @@ class Profile(models.Model):
|
||||
default='',
|
||||
)
|
||||
|
||||
class AuthToken(models.Model):
|
||||
class AuthToken(BaseModel):
|
||||
'''
|
||||
Custom authentication tokens per user with expiration and request-specific
|
||||
data.
|
||||
|
||||
@@ -509,7 +509,13 @@ class ProjectsTest(BaseTest):
|
||||
data = dict(name='zyx', user=self.super_django_user.pk, kind='ssh',
|
||||
sudo_username=None)
|
||||
self.post(url, data, expect=400)
|
||||
|
||||
|
||||
# Test with encrypted ssh key and no unlock password.
|
||||
with self.current_user(self.super_django_user):
|
||||
data = dict(name='zyx', user=self.super_django_user.pk, kind='ssh',
|
||||
ssh_key_data=TEST_SSH_KEY_DATA_LOCKED)
|
||||
self.post(url, data, expect=400)
|
||||
|
||||
# FIXME: Check list as other users.
|
||||
|
||||
# can edit a credential
|
||||
|
||||
Reference in New Issue
Block a user