Add support for magic "admin" ACL that is only satisfied by appengine administrators.

This commit is contained in:
Ian Gulliver
2014-06-08 23:41:23 -07:00
parent 44ede2abbf
commit d2e7b76df9
2 changed files with 90 additions and 6 deletions

View File

@@ -19,6 +19,7 @@ import logging
import struct import struct
from google.appengine.api import channel from google.appengine.api import channel
from google.appengine.api import users
from google.appengine.ext import db from google.appengine.ext import db
import utils import utils
@@ -49,6 +50,8 @@ class Profile(db.Model):
_cache = {} _cache = {}
ADMIN_KEY = db.Key.from_path('Profile', 'admin')
@classmethod @classmethod
@db.transactional() @db.transactional()
def FindOrCreate(cls, google_user): def FindOrCreate(cls, google_user):
@@ -125,12 +128,18 @@ class Subject(db.Model):
@classmethod @classmethod
def FindOrCreate(cls, subject): def FindOrCreate(cls, subject):
if 'readable_only_by' in subject: if 'readable_only_by' in subject:
readable_only_by = db.Key(subject['readable_only_by']) if subject['readable_only_by'] == 'admin':
readable_only_by = Profile.ADMIN_KEY
else:
readable_only_by = db.Key(subject['readable_only_by'])
else: else:
readable_only_by = None readable_only_by = None
if 'writable_only_by' in subject: if 'writable_only_by' in subject:
writable_only_by = db.Key(subject['writable_only_by']) if subject['writable_only_by'] == 'admin':
writable_only_by = Profile.ADMIN_KEY
else:
writable_only_by = db.Key(subject['writable_only_by'])
else: else:
writable_only_by = None writable_only_by = None
@@ -213,13 +222,15 @@ class Subject(db.Model):
def VerifyWritable(self, sender): def VerifyWritable(self, sender):
writable_only_by = Subject.writable_only_by.get_value_for_datastore(self) writable_only_by = Subject.writable_only_by.get_value_for_datastore(self)
if (writable_only_by and if (not users.is_current_user_admin() and
writable_only_by and
writable_only_by != sender): writable_only_by != sender):
raise AccessDenied raise AccessDenied
def VerifyReadable(self, reader): def VerifyReadable(self, reader):
readable_only_by = Subject.readable_only_by.get_value_for_datastore(self) readable_only_by = Subject.readable_only_by.get_value_for_datastore(self)
if (readable_only_by and if (not users.is_current_user_admin() and
readable_only_by and
readable_only_by != reader): readable_only_by != reader):
raise AccessDenied raise AccessDenied
@@ -294,10 +305,16 @@ class Subject(db.Model):
} }
readable_only_by = Subject.readable_only_by.get_value_for_datastore(self) readable_only_by = Subject.readable_only_by.get_value_for_datastore(self)
if readable_only_by: if readable_only_by:
ret['readable_only_by'] = str(readable_only_by) if readable_only_by == Profile.ADMIN_KEY:
ret['readable_only_by'] = 'admin'
else:
ret['readable_only_by'] = str(readable_only_by)
writable_only_by = Subject.writable_only_by.get_value_for_datastore(self) writable_only_by = Subject.writable_only_by.get_value_for_datastore(self)
if writable_only_by: if writable_only_by:
ret['writable_only_by'] = str(writable_only_by) if writable_only_by == Profile.ADMIN_KEY:
ret['writable_only_by'] = 'admin'
else:
ret['writable_only_by'] = str(writable_only_by)
return ret return ret
@db.transactional() @db.transactional()

View File

@@ -629,3 +629,70 @@ asyncTest('Two channels, one client', function() {
}); });
}); });
}); });
asyncTest('subscribe admin ACL', function() {
expect(2);
var subject = randstring();
logout(function() {
var callbacks = {
'onLogin': function() {
cosmo.subscribe({
'name': subject,
'readable_only_by': 'admin'
}).then(function() {
ok(true, 'logged in succeeds');
cosmo.shutdown();
start();
});
}
};
var cosmo = new Cosmopolite(callbacks, null, randstring());
cosmo.subscribe({
'name': subject,
'readable_only_by': 'admin'
}).then(null, function() {
ok(true, 'logged out fails');
window.open(
'/_ah/login?email=test%40example.com&admin=True&action=Login' +
'&continue=/cosmopolite/static/login_complete.html');
});
});
});
asyncTest('sendMessage admin ACL', function() {
expect(2);
var subject = randstring();
var message = randstring();
logout(function() {
var callbacks = {
'onLogin': function() {
cosmo.sendMessage({
'name': subject,
'writable_only_by': 'admin'
}, message).then(function() {
ok(true, 'logged in succeeds');
cosmo.shutdown();
start();
});
}
};
var cosmo = new Cosmopolite(callbacks, null, randstring());
cosmo.sendMessage({
'name': subject,
'writable_only_by': 'admin'
}, message).then(null, function() {
ok(true, 'logged out fails');
window.open(
'/_ah/login?email=test%40example.com&admin=True&action=Login' +
'&continue=/cosmopolite/static/login_complete.html');
});
});
});