Commit 726c6897 by Őry Máté

dashboard: add TokenOperationView

parent 41195564
...@@ -47,7 +47,12 @@ ...@@ -47,7 +47,12 @@
</dl> </dl>
<h4>{% trans "Expiration" %} {% if instance.is_expiring %}<i class="icon-warning-sign text-danger"></i>{% endif %} <h4>{% trans "Expiration" %} {% if instance.is_expiring %}<i class="icon-warning-sign text-danger"></i>{% endif %}
<a href="{% url "dashboard.views.vm-renew" instance.pk "" %}" class="btn btn-success btn-xs pull-right">{% trans "renew" %}</a> {% with op=op.renew %}
<a href="{{op.get_url}}" class="btn btn-success btn-xs
operation operation-{{op.op}} btn btn-default">
<i class="icon-{{op.icon}}"></i>
{{op.name}} </a>
{% endwith %}
</h4> </h4>
<dl> <dl>
<dt>{% trans "Suspended at:" %}</dt> <dt>{% trans "Suspended at:" %}</dt>
......
...@@ -728,6 +728,81 @@ class VmResourcesChangeView(VmOperationView): ...@@ -728,6 +728,81 @@ class VmResourcesChangeView(VmOperationView):
*args, **kwargs) *args, **kwargs)
class TokenOperationView(OperationView):
"""Abstract operation view with token support.
User can do the action with a valid token instead of logging in.
"""
token_max_age = 3 * 24 * 3600
@classmethod
def get_salt(cls):
return unicode(cls)
@classmethod
def get_token(cls, instance, user):
t = tuple([getattr(i, 'pk', i) for i in [instance, user]])
return signing.dumps(t, salt=cls.get_salt(), compress=True)
@classmethod
def get_token_url(cls, instance, user):
key = cls.get_token(instance, user)
return cls.get_instance_url(instance.pk, key)
def check_auth(self):
if 'k' in self.request.GET:
try: # check if token is needed at all
return super(TokenOperationView, self).check_auth()
except Exception:
op = self.get_op()
pk = op.instance.pk
key = self.request.GET.get('k')
logger.debug("checking token supplied to %s",
self.request.get_full_path())
try:
user = self.validate_key(pk, key)
except signing.SignatureExpired:
messages.error(self.request, _('The token has expired.'))
else:
logger.info("Request user changed to %s at %s",
user, self.request.get_full_path())
self.request.user = user
else:
logger.debug("no token supplied to %s",
self.request.get_full_path())
return super(TokenOperationView, self).check_auth()
def validate_key(self, pk, key):
"""Get object based on signed token.
"""
try:
data = signing.loads(key, salt=self.get_salt())
logger.debug('Token data: %s', unicode(data))
instance, user = data
logger.debug('Extracted token data: instance: %s, user: %s',
unicode(instance), unicode(user))
except (signing.BadSignature, ValueError, TypeError) as e:
logger.warning('Tried invalid token. Token: %s, user: %s. %s',
key, unicode(self.request.user), unicode(e))
raise SuspiciousOperation()
try:
instance, user = signing.loads(key, max_age=self.token_max_age,
salt=self.get_salt())
logger.debug('Extracted non-expired token data: %s, %s',
unicode(instance), unicode(user))
except signing.BadSignature as e:
raise signing.SignatureExpired()
if pk != instance:
logger.debug('pk (%d) != instance (%d)', pk, instance)
raise SuspiciousOperation()
user = User.objects.get(pk=user)
return user
vm_ops = OrderedDict([ vm_ops = OrderedDict([
('deploy', VmOperationView.factory( ('deploy', VmOperationView.factory(
op='deploy', icon='play', effect='success')), op='deploy', icon='play', effect='success')),
...@@ -751,6 +826,9 @@ vm_ops = OrderedDict([ ...@@ -751,6 +826,9 @@ vm_ops = OrderedDict([
op='destroy', icon='remove', effect='danger')), op='destroy', icon='remove', effect='danger')),
('create_disk', VmCreateDiskView), ('create_disk', VmCreateDiskView),
('download_disk', VmDownloadDiskView), ('download_disk', VmDownloadDiskView),
('renew', VmOperationView.factory(
op='renew', icon='calendar', extra_bases=[TokenOperationView],
show_in_toolbar=False)),
]) ])
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment