Add permissions to API keys

This commit is contained in:
2012-06-08 20:32:06 +01:00
parent 799cd0231b
commit 5180712cef
6 changed files with 146 additions and 14 deletions

View File

@@ -5,6 +5,7 @@ class AuthAPIKeyAdmin(admin.ModelAdmin):
list_display = ('key', 'name', 'url', 'active') list_display = ('key', 'name', 'url', 'active')
search_fields = ['name'] search_fields = ['name']
list_filter = ('active',) list_filter = ('active',)
filter_horizontal = ('permissions',)
class AuthAPILogAdmin(admin.ModelAdmin): class AuthAPILogAdmin(admin.ModelAdmin):

View File

@@ -4,6 +4,7 @@ from datetime import datetime
from django.http import HttpResponseForbidden from django.http import HttpResponseForbidden
from django.contrib.auth.models import AnonymousUser from django.contrib.auth.models import AnonymousUser
from django.utils.timezone import now from django.utils.timezone import now
from django.core.urlresolvers import resolve
from api.models import AuthAPIKey, AuthAPILog from api.models import AuthAPIKey, AuthAPILog
@@ -15,7 +16,7 @@ class APIKeyAuthentication(object):
try: try:
keyobj = AuthAPIKey.objects.get(key=request.GET.get('apikey', None)) keyobj = AuthAPIKey.objects.get(key=request.GET.get('apikey', None))
except AuthAPIKey.DoesNotExist: except AuthAPIKey.DoesNotExist:
pass return False
else: else:
if keyobj and keyobj.active: if keyobj and keyobj.active:
params = request.GET.copy() params = request.GET.copy()
@@ -24,6 +25,8 @@ class APIKeyAuthentication(object):
url = "%s?%s" % (request.path, urlencode(params)) url = "%s?%s" % (request.path, urlencode(params))
else: else:
url = request.path url = request.path
if not keyobj.permissions.filter(key=resolve(request.path).url_name).count():
return False
AuthAPILog.objects.create(key=keyobj, access_datetime=now(), url=url) AuthAPILog.objects.create(key=keyobj, access_datetime=now(), url=url)
request.user = AnonymousUser() request.user = AnonymousUser()
request.api_key = keyobj request.api_key = keyobj
@@ -31,4 +34,4 @@ class APIKeyAuthentication(object):
return False return False
def challenge(self): def challenge(self):
return HttpResponseForbidden('Access Denied, use a API Key') return HttpResponseForbidden('Access Denied, use a valid API Key for this request.')

View File

@@ -0,0 +1,60 @@
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'AuthAPIKeyPermission'
db.create_table('api_authapikeypermission', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('key', self.gf('django.db.models.fields.CharField')(max_length=32)),
('name', self.gf('django.db.models.fields.CharField')(max_length=200)),
))
db.send_create_signal('api', ['AuthAPIKeyPermission'])
# Adding M2M table for field permissions on 'AuthAPIKey'
db.create_table('api_authapikey_permissions', (
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
('authapikey', models.ForeignKey(orm['api.authapikey'], null=False)),
('authapikeypermission', models.ForeignKey(orm['api.authapikeypermission'], null=False))
))
db.create_unique('api_authapikey_permissions', ['authapikey_id', 'authapikeypermission_id'])
def backwards(self, orm):
# Deleting model 'AuthAPIKeyPermission'
db.delete_table('api_authapikeypermission')
# Removing M2M table for field permissions on 'AuthAPIKey'
db.delete_table('api_authapikey_permissions')
models = {
'api.authapikey': {
'Meta': {'object_name': 'AuthAPIKey'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'callback': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'keys'", 'symmetrical': 'False', 'to': "orm['api.AuthAPIKeyPermission']"}),
'url': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'})
},
'api.authapikeypermission': {
'Meta': {'object_name': 'AuthAPIKeyPermission'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'key': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '200'})
},
'api.authapilog': {
'Meta': {'ordering': "['access_datetime']", 'object_name': 'AuthAPILog'},
'access_datetime': ('django.db.models.fields.DateTimeField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'key': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['api.AuthAPIKey']"}),
'url': ('django.db.models.fields.CharField', [], {'max_length': '200'})
}
}
complete_apps = ['api']

View File

@@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import DataMigration
from django.db import models
class Migration(DataMigration):
def forwards(self, orm):
from api.urls import urlpatterns as urls
for u in urls:
if not u.name is None:
orm['api.AuthAPIKeyPermission'].objects.get_or_create(key=u.name, name=u.name)
perms = orm['api.AuthAPIKeyPermission'].objects.all()
for key in orm['api.AuthAPIKey'].objects.all():
key.permissions.add(*perms)
def backwards(self, orm):
for key in orm['api.AuthAPIKey'].objects.all():
key.permissions.clear()
orm['api.AuthAPIKeyPermission'].objects.all().delete()
models = {
'api.authapikey': {
'Meta': {'object_name': 'AuthAPIKey'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'callback': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'keys'", 'symmetrical': 'False', 'to': "orm['api.AuthAPIKeyPermission']"}),
'url': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'})
},
'api.authapikeypermission': {
'Meta': {'object_name': 'AuthAPIKeyPermission'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'key': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '200'})
},
'api.authapilog': {
'Meta': {'ordering': "['access_datetime']", 'object_name': 'AuthAPILog'},
'access_datetime': ('django.db.models.fields.DateTimeField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'key': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['api.AuthAPIKey']"}),
'url': ('django.db.models.fields.CharField', [], {'max_length': '200'})
}
}
complete_apps = ['api']
symmetrical = True

View File

@@ -2,14 +2,28 @@ import uuid
from django.db import models from django.db import models
class AuthAPIKeyPermission(models.Model):
""" Auth API Key permissions """
key = models.CharField("Permission Key", max_length=32)
name = models.CharField("Permission Name", max_length=200)
def __unicode__(self):
return self.name
class Meta:
verbose_name = 'API Key Permission'
verbose_name_plural = 'API Key Permissions'
class AuthAPIKey(models.Model): class AuthAPIKey(models.Model):
""" Auth API Key storage model """ """ Auth API Key storage model """
name = models.CharField("Service Name", max_length=200) name = models.CharField("Service Name", max_length=200)
url = models.CharField("Service URL", max_length=200, blank=True, help_text="URL that the service is available at") url = models.CharField("Service URL", max_length=200, blank=True, help_text="URL that the service is available at.")
active = models.BooleanField(default=True) active = models.BooleanField(default=True)
key = models.CharField("API Key", max_length=200, blank=True, help_text="API key for the service to use") key = models.CharField("API Key", max_length=200, blank=True, help_text="API key for the service to use.")
callback = models.CharField("Callback URL", max_length=200, blank=True, help_text="URL for the callback service to connect to") callback = models.CharField("Callback URL", max_length=200, blank=True, help_text="URL for the callback service to connect to.")
permissions = models.ManyToManyField(AuthAPIKeyPermission, related_name='keys', help_text="API calls this API key is allowed to access.")
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if not self.key or self.key == '': if not self.key or self.key == '':

View File

@@ -21,15 +21,15 @@ announce_resource = Resource(handler=AnnounceHandler, **apikeyauth)
edkapi_resource = Resource(handler=EDKApiHandler, **apikeyauth) edkapi_resource = Resource(handler=EDKApiHandler, **apikeyauth)
urlpatterns = patterns('', urlpatterns = patterns('',
url(r'^1.0/user/$', user_resource), url(r'^1.0/user/$', user_resource, name='v1-api-user'),
url(r'^1.0/login/$', login_resource), url(r'^1.0/login/$', login_resource, name='v1-api-login'),
url(r'^1.0/eveapi/$', eveapi_resource), url(r'^1.0/eveapi/$', eveapi_resource, name='v1-api-eveapi'),
url(r'^1.0/eveapi/', eveapiproxy_resource, name='api-eveapiproxy'), url(r'^1.0/eveapi/', eveapiproxy_resource, name='v1-api-eveapiproxy'),
url(r'^1.0/character/$', characters_resource), url(r'^1.0/character/$', characters_resource, name='v1-api-character'),
url(r'^1.0/optimer/$', optimer_resource), url(r'^1.0/optimer/$', optimer_resource, name='v1-api-optimer'),
url(r'^1.0/blacklist/$', blacklist_resource), url(r'^1.0/blacklist/$', blacklist_resource, name='v1-api-blacklist'),
url(r'^1.0/announce/$', announce_resource), url(r'^1.0/announce/$', announce_resource, name='v1-api-announce'),
url(r'^1.0/edkapi/$', edkapi_resource), url(r'^1.0/edkapi/$', edkapi_resource, name='v1-api-edkapi'),
) )
# v2 APIs # v2 APIs