[logic,auth] Add auth logic layer

The first version of the auth layer is based on the current policy, i.e.
you need to be sysadmin to perform any action.

TODO: the CLI is still not working.
This commit is contained in:
amercader 2012-03-01 12:02:16 +00:00
parent c798013752
commit a35eb75440
12 changed files with 289 additions and 49 deletions

View File

@ -152,12 +152,11 @@ class Harvester(CkanCommand):
'user_id':user_id,
'publisher_id':publisher_id}
context = {'model':model}
context = {'model':model, 'session':model.Session}
source = get_action('harvest_source_create')(context,data_dict)
print 'Created new harvest source:'
self.print_harvest_source(source)
context = {'model': model}
sources = get_action('harvest_source_list')(context,{})
self.print_there_are('harvest source', sources)
@ -189,7 +188,7 @@ class Harvester(CkanCommand):
data_dict = {'only_active':True}
what = 'active harvest source'
context = {'model': model}
context = {'model': model,'session':model.Session}
sources = get_action('harvest_source_list')(context,data_dict)
self.print_harvest_sources(sources)
self.print_there_are(what=what, sequence=sources)
@ -204,7 +203,7 @@ class Harvester(CkanCommand):
job = create_harvest_job(source_id)
self.print_harvest_job(job)
context = {'model': model}
context = {'model': model,'session':model.Session}
jobs = get_action('harvest_job_list')(context,{'status':u'New'})
self.print_there_are('harvest jobs', jobs, condition=status)
@ -226,7 +225,7 @@ class Harvester(CkanCommand):
source_id = unicode(self.args[1])
else:
source_id = None
context = {'model': model}
context = {'model': model, 'session':model.Session}
objs = get_action('harvest_objects_import')(context,{'source_id':source_id})
print '%s objects reimported' % len(objs)

View File

@ -9,7 +9,7 @@ from ckan.lib.base import BaseController, c, g, request, \
response, session, render, config, abort, redirect
from ckan.lib.navl.dictization_functions import DataError
from ckan.logic import NotFound, ValidationError, get_action
from ckan.logic import NotFound, ValidationError, get_action, NotAuthorized
from ckanext.harvest.logic.schema import harvest_source_form_schema
from ckan.lib.helpers import Page
import logging
@ -17,19 +17,15 @@ log = logging.getLogger(__name__)
class ViewController(BaseController):
def __before__(self, action, **env):
super(ViewController, self).__before__(action, **env)
# All calls to this controller must be with a sysadmin key
if not self.authorizer.is_sysadmin(c.user):
response_msg = _('Not authorized to see this page')
status = 401
abort(status, response_msg)
not_auth_message = _('Not authorized to see this page')
def index(self):
# Request all harvest sources
context = {'model':model}
c.sources = get_action('harvest_source_list')(context,{})
context = {'model':model, 'user':c.user,'session':model.Session}
try:
# Request all harvest sources
c.sources = get_action('harvest_source_list')(context,{})
except NotAuthorized,e:
abort(401,self.not_auth_message)
return render('index.html')
@ -41,7 +37,13 @@ class ViewController(BaseController):
data = data or {}
errors = errors or {}
error_summary = error_summary or {}
harvesters_info = get_action('harvesters_info_show')()
try:
context = {'model':model, 'user':c.user}
harvesters_info = get_action('harvesters_info_show')(context,{})
except NotAuthorized,e:
abort(401,self.not_auth_message)
vars = {'data': data, 'errors': errors, 'error_summary': error_summary, 'harvesters': harvesters_info}
c.form = render('source/new_source_form.html', extra_vars=vars)
@ -51,8 +53,7 @@ class ViewController(BaseController):
try:
data_dict = dict(request.params)
self._check_data_dict(data_dict)
context = {'model':model}
context = {'model':model, 'user':c.user, 'session':model.Session}
source = get_action('harvest_source_create')(context,data_dict)
# Create a harvest job for the new source
@ -61,6 +62,8 @@ class ViewController(BaseController):
h.flash_success(_('New harvest source added successfully.'
'A new harvest job for the source has also been created.'))
redirect(h.url_for('harvest'))
except NotAuthorized,e:
abort(401,self.not_auth_message)
except DataError,e:
abort(400, 'Integrity Error')
except ValidationError,e:
@ -76,17 +79,23 @@ class ViewController(BaseController):
if not data:
try:
context = {'model':model}
context = {'model':model, 'user':c.user}
old_data = get_action('harvest_source_show')(context, {'id':id})
except NotFound:
abort(404, _('Harvest Source not found'))
except NotAuthorized,e:
abort(401,self.not_auth_message)
data = data or old_data
errors = errors or {}
error_summary = error_summary or {}
try:
context = {'model':model, 'user':c.user}
harvesters_info = get_action('harvesters_info_show')(context,{})
except NotAuthorized,e:
abort(401,self.not_auth_message)
harvesters_info = get_action('harvesters_info_show')()
vars = {'data': data, 'errors': errors, 'error_summary': error_summary, 'harvesters': harvesters_info}
c.form = render('source/new_source_form.html', extra_vars=vars)
@ -97,12 +106,14 @@ class ViewController(BaseController):
data_dict = dict(request.params)
data_dict['id'] = id
self._check_data_dict(data_dict)
context = {'model':model}
context = {'model':model, 'user':c.user, 'session':model.Session}
source = get_action('harvest_source_update')(context,data_dict)
h.flash_success(_('Harvest source edited successfully.'))
redirect(h.url_for('harvest'))
except NotAuthorized,e:
abort(401,self.not_auth_message)
except DataError,e:
abort(400, _('Integrity Error'))
except NotFound, e:
@ -125,7 +136,7 @@ class ViewController(BaseController):
def read(self,id):
try:
context = {'model':model}
context = {'model':model, 'user':c.user}
c.source = get_action('harvest_source_show')(context, {'id':id})
c.page = Page(
@ -137,26 +148,33 @@ class ViewController(BaseController):
return render('source/read.html')
except NotFound:
abort(404,_('Harvest source not found'))
except NotAuthorized,e:
abort(401,self.not_auth_message)
def delete(self,id):
try:
context = {'model':model}
context = {'model':model, 'user':c.user}
get_action('harvest_source_delete')(context, {'id':id})
h.flash_success(_('Harvesting source successfully inactivated'))
redirect(h.url_for('harvest'))
except NotFound:
abort(404,_('Harvest source not found'))
except NotAuthorized,e:
abort(401,self.not_auth_message)
def create_harvesting_job(self,id):
try:
context = {'model':model}
context = {'model':model, 'user':c.user, 'session':model.Session}
get_action('harvest_job_create')(context,{'source_id':id})
h.flash_success(_('Refresh requested, harvesting will take place within 15 minutes.'))
except NotFound:
abort(404,_('Harvest source not found'))
except NotAuthorized,e:
abort(401,self.not_auth_message)
except Exception, e:
msg = 'An error occurred: [%s]' % e.message
h.flash_error(msg)
@ -164,8 +182,9 @@ class ViewController(BaseController):
redirect(h.url_for('harvest'))
def show_object(self,id):
try:
context = {'model':model}
context = {'model':model, 'user':c.user}
obj = get_action('harvest_object_show')(context, {'id':id})
# Check content type. It will probably be either XML or JSON
@ -183,6 +202,8 @@ class ViewController(BaseController):
return obj['content']
except NotFound:
abort(404,_('Harvest object not found'))
except NotAuthorized,e:
abort(401,self.not_auth_message)
except Exception, e:
msg = 'An error occurred: [%s]' % e.message
h.flash_error(msg)

View File

@ -1,6 +1,6 @@
import re
from ckan.logic import NotFound, ValidationError
from ckan.logic import NotFound, ValidationError, check_access
from ckan.lib.navl.dictization_functions import validate
from ckanext.harvest.model import (HarvestSource, HarvestJob, HarvestObject)
@ -11,13 +11,16 @@ from ckanext.harvest.logic.action.get import harvest_source_list,harvest_job_lis
def harvest_source_create(context,data_dict):
check_access('harvest_source_create',context,data_dict)
model = context['model']
session = context['session']
schema = harvest_source_form_schema()
data, errors = validate(data_dict, schema)
if errors:
model.Session.rollback()
session.rollback()
raise ValidationError(errors,_error_summary(errors))
source = HarvestSource()
@ -38,6 +41,8 @@ def harvest_source_create(context,data_dict):
def harvest_job_create(context,data_dict):
check_access('harvest_job_create',context,data_dict)
source_id = data_dict['source_id']
# Check if source exists
@ -66,6 +71,8 @@ def harvest_job_create(context,data_dict):
def harvest_job_create_all(context,data_dict):
check_access('harvest_job_create_all',context,data_dict)
data_dict.update({'only_active':True})
# Get all active sources

View File

@ -1,10 +1,12 @@
from ckan.logic import NotFound
from ckan.logic import NotFound, check_access
from ckanext.harvest.model import (HarvestSource, HarvestJob)
def harvest_source_delete(context,data_dict):
check_access('harvest_source_delete',context,data_dict)
source_id = data_dict.get('id')
source = HarvestSource.get(source_id)
if not source:

View File

@ -2,7 +2,7 @@ from ckan.plugins import PluginImplementations
from ckanext.harvest.interfaces import IHarvester
from ckan.logic import NotFound
from ckan.logic import NotFound, check_access
from ckanext.harvest.model import (HarvestSource, HarvestJob, HarvestObject)
from ckanext.harvest.logic.dictization import (harvest_source_dictize,
@ -11,6 +11,8 @@ from ckanext.harvest.logic.dictization import (harvest_source_dictize,
def harvest_source_show(context,data_dict):
check_access('harvest_source_show',context,data_dict)
id = data_dict.get('id')
attr = data_dict.get('attr',None)
@ -23,17 +25,20 @@ def harvest_source_show(context,data_dict):
def harvest_source_list(context, data_dict):
check_access('harvest_source_list',context,data_dict)
model = context['model']
session = context['session']
only_active = data_dict.get('only_active',False)
if only_active:
sources = model.Session.query(HarvestSource) \
sources = session.query(HarvestSource) \
.filter(HarvestSource.active==True) \
.order_by(HarvestSource.created.desc()) \
.all()
else:
sources = model.Session.query(HarvestSource) \
sources = session.query(HarvestSource) \
.order_by(HarvestSource.created.desc()) \
.all()
@ -42,6 +47,8 @@ def harvest_source_list(context, data_dict):
def harvest_job_show(context,data_dict):
check_access('harvest_job_show',context,data_dict)
id = data_dict.get('id')
attr = data_dict.get('attr',None)
@ -53,12 +60,15 @@ def harvest_job_show(context,data_dict):
def harvest_job_list(context,data_dict):
check_access('harvest_job_list',context,data_dict)
model = context['model']
session = context['session']
source_id = data_dict.get('source_id',False)
status = data_dict.get('status',False)
query = model.Session.query(HarvestJob)
query = session.query(HarvestJob)
if source_id:
query = query.filter(HarvestJob.source_id==source_id)
@ -72,9 +82,10 @@ def harvest_job_list(context,data_dict):
def harvest_object_show(context,data_dict):
check_access('harvest_object_show',context,data_dict)
id = data_dict.get('id')
attr = data_dict.get('attr',None)
obj = HarvestObject.get(id,attr=attr)
if not obj:
raise NotFound
@ -83,20 +94,26 @@ def harvest_object_show(context,data_dict):
def harvest_object_list(context,data_dict):
check_access('harvest_object_list',context,data_dict)
model = context['model']
session = context['session']
only_current = data_dict.get('only_current',True)
if only_current:
objects = model.Session.query(HarvestObject) \
objects = session.query(HarvestObject) \
.filter(HarvestObject.current==True) \
.all()
else:
objects = model.Session.query(HarvestObject).all()
objects = session.query(HarvestObject).all()
return [getattr(obj,'id') for obj in objects]
def harvesters_info_show(context = {},data_dict = {}):
def harvesters_info_show(context,data_dict):
check_access('harvesters_info_show',context,data_dict)
available_harvesters = []
for harvester in PluginImplementations(IHarvester):
info = harvester.info()

View File

@ -5,7 +5,7 @@ from ckanext.harvest.interfaces import IHarvester
from ckan.model import Package
from ckan.logic import NotFound, ValidationError
from ckan.logic import NotFound, ValidationError, check_access
from ckan.lib.navl.dictization_functions import validate
from ckanext.harvest.queue import get_gather_publisher
@ -22,7 +22,11 @@ log = logging.getLogger(__name__)
def harvest_source_update(context,data_dict):
check_access('harvest_source_update',context,data_dict)
model = context['model']
session = context['session']
source_id = data_dict.get('id')
schema = harvest_source_form_schema()
@ -33,7 +37,7 @@ def harvest_source_update(context,data_dict):
data, errors = validate(data_dict, schema)
if errors:
model.Session.rollback()
session.rollback()
raise ValidationError(errors,_error_summary(errors))
fields = ['url','title','type','description','user_id','publisher_id']
@ -67,7 +71,10 @@ def harvest_objects_import(context,data_dict):
It will only affect the last fetched objects already present in the
database.
'''
check_access('harvest_objects_import',context,data_dict)
model = context['model']
session = context['session']
source_id = data_dict.get('source_id',None)
if source_id:
@ -78,14 +85,14 @@ def harvest_objects_import(context,data_dict):
if not source.active:
raise Exception('This harvest source is not active')
last_objects_ids = model.Session.query(HarvestObject.id) \
last_objects_ids = session.query(HarvestObject.id) \
.join(HarvestSource).join(Package) \
.filter(HarvestObject.source==source) \
.filter(HarvestObject.current==True) \
.filter(Package.state==u'active') \
.all()
else:
last_objects_ids = model.Session.query(HarvestObject.id) \
last_objects_ids = session.query(HarvestObject.id) \
.join(Package) \
.filter(HarvestObject.current==True) \
.filter(Package.state==u'active') \
@ -93,7 +100,7 @@ def harvest_objects_import(context,data_dict):
last_objects = []
for obj_id in last_objects_ids:
obj = model.Session.query(HarvestObject).get(obj_id)
obj = session.query(HarvestObject).get(obj_id)
for harvester in PluginImplementations(IHarvester):
if harvester.info()['name'] == obj.source.type:
if hasattr(harvester,'force_import'):
@ -105,6 +112,8 @@ def harvest_objects_import(context,data_dict):
def harvest_jobs_run(context,data_dict):
check_access('harvest_jobs_run',context,data_dict)
# Check if there are pending harvest jobs
jobs = harvest_job_list(context,{'status':u'New'})
if len(jobs) == 0:

View File

@ -0,0 +1,7 @@
try:
import pkg_resources
pkg_resources.declare_namespace(__name__)
except ImportError:
import pkgutil
__path__ = pkgutil.extend_path(__path__, __name__)

View File

@ -0,0 +1,30 @@
from ckan.lib.base import _
from ckan.authz import Authorizer
def harvest_source_create(context,data_dict):
model = context['model']
user = context.get('user')
if not Authorizer().is_sysadmin(user):
return {'success': False, 'msg': _('User %s not authorized to create harvest sources') % str(user)}
else:
return {'success': True}
def harvest_job_create(context,data_dict):
model = context['model']
user = context.get('user')
if not Authorizer().is_sysadmin(user):
return {'success': False, 'msg': _('User %s not authorized to create harvest jobs') % str(user)}
else:
return {'success': True}
def harvest_job_create_all(context,data_dict):
model = context['model']
user = context.get('user')
if not Authorizer().is_sysadmin(user):
return {'success': False, 'msg': _('User %s not authorized to create harvest jobs for all sources') % str(user)}
else:
return {'success': True}

View File

@ -0,0 +1,13 @@
from ckan.lib.base import _
from ckan.authz import Authorizer
def harvest_source_delete(context,data_dict):
model = context['model']
user = context.get('user')
if not Authorizer().is_sysadmin(user):
return {'success': False, 'msg': _('User %s not authorized to delete harvest sources') % str(user)}
else:
return {'success': True}

View File

@ -0,0 +1,67 @@
from ckan.lib.base import _
from ckan.authz import Authorizer
def harvest_source_show(context,data_dict):
model = context['model']
user = context.get('user')
if not Authorizer().is_sysadmin(user):
return {'success': False, 'msg': _('User %s not authorized to read this harvest source') % str(user)}
else:
return {'success': True}
def harvest_source_list(context,data_dict):
model = context['model']
user = context.get('user')
if not Authorizer().is_sysadmin(user):
return {'success': False, 'msg': _('User %s not authorized to see the harvest sources') % str(user)}
else:
return {'success': True}
def harvest_job_show(context,data_dict):
model = context['model']
user = context.get('user')
if not Authorizer().is_sysadmin(user):
return {'success': False, 'msg': _('User %s not authorized to read this harvest job') % str(user)}
else:
return {'success': True}
def harvest_job_list(context,data_dict):
model = context['model']
user = context.get('user')
if not Authorizer().is_sysadmin(user):
return {'success': False, 'msg': _('User %s not authorized to see the harvest jobs') % str(user)}
else:
return {'success': True}
def harvest_object_show(context,data_dict):
model = context['model']
user = context.get('user')
if not Authorizer().is_sysadmin(user):
return {'success': False, 'msg': _('User %s not authorized to read this harvest object') % str(user)}
else:
return {'success': True}
def harvest_object_list(context,data_dict):
model = context['model']
user = context.get('user')
if not Authorizer().is_sysadmin(user):
return {'success': False, 'msg': _('User %s not authorized to see the harvest objects') % str(user)}
else:
return {'success': True}
def harvesters_info_show(context,data_dict):
model = context['model']
user = context.get('user')
if not Authorizer().is_sysadmin(user):
return {'success': False, 'msg': _('User %s not authorized to see the harvesters information') % str(user)}
else:
return {'success': True}

View File

@ -0,0 +1,30 @@
from ckan.lib.base import _
from ckan.authz import Authorizer
def harvest_source_update(context,data_dict):
model = context['model']
user = context.get('user')
if not Authorizer().is_sysadmin(user):
return {'success': False, 'msg': _('User %s not authorized to update harvest sources') % str(user)}
else:
return {'success': True}
def harvest_objects_import(context,data_dict):
model = context['model']
user = context.get('user')
if not Authorizer().is_sysadmin(user):
return {'success': False, 'msg': _('User %s not authorized to reimport harvest objects') % str(user)}
else:
return {'success': True}
def harvest_jobs_run(context,data_dict):
model = context['model']
user = context.get('user')
if not Authorizer().is_sysadmin(user):
return {'success': False, 'msg': _('User %s not authorized to run the pending harvest jobs') % str(user)}
else:
return {'success': True}

View File

@ -8,18 +8,18 @@ import ckan.lib.helpers as h
from ckan.plugins import implements, SingletonPlugin
from ckan.plugins import IRoutes, IConfigurer
from ckan.plugins import IConfigurable, IActions
from ckan.plugins import IConfigurable, IActions, IAuthFunctions
from ckanext.harvest.model import setup
log = getLogger(__name__)
class Harvest(SingletonPlugin):
implements(IConfigurable)
implements(IRoutes, inherit=True)
implements(IConfigurer, inherit=True)
implements(IActions)
implements(IAuthFunctions)
def configure(self, config):
setup()
@ -30,11 +30,11 @@ class Harvest(SingletonPlugin):
map.connect('harvest', '/harvest',controller=controller,action='index')
map.connect('/harvest/new', controller=controller, action='new')
map.connect('/harvest/edit/:id', controller=controller, action='edit')
map.connect('/harvest/edit/:id', controller=controller, action='edit')
map.connect('/harvest/delete/:id',controller=controller, action='delete')
map.connect('/harvest/:id', controller=controller, action='read')
map.connect('harvesting_job_create', '/harvest/refresh/:id',controller=controller,
map.connect('harvesting_job_create', '/harvest/refresh/:id',controller=controller,
action='create_harvesting_job')
map.connect('/harvest/object/:id', controller=controller, action='show_object')
@ -59,6 +59,8 @@ class Harvest(SingletonPlugin):
harvest_source_list,
harvest_job_show,
harvest_job_list,
harvest_object_show,
harvest_object_list,
harvesters_info_show,)
from ckanext.harvest.logic.action.create import (harvest_source_create,
harvest_job_create,
@ -73,12 +75,48 @@ class Harvest(SingletonPlugin):
'harvest_source_list': harvest_source_list,
'harvest_job_show': harvest_job_show,
'harvest_job_list': harvest_job_list,
'harvest_object_show': harvest_object_show,
'harvest_object_list': harvest_object_list,
'harvesters_info_show': harvesters_info_show,
'harvest_source_create': harvest_source_create,
'harvest_job_create': harvest_job_create,
'harvest_job_create_all': harvest_job_create_all,
'harvest_source_update': harvest_source_update,
'harvest_source_delete': harvest_source_delete,
'harvesters_info_show': harvesters_info_show,
'harvest_objects_import': harvest_objects_import,
'harvest_jobs_run':harvest_jobs_run
}
def get_auth_functions(self):
from ckanext.harvest.logic.auth.get import (harvest_source_show,
harvest_source_list,
harvest_job_show,
harvest_job_list,
harvest_object_show,
harvest_object_list,
harvesters_info_show,)
from ckanext.harvest.logic.auth.create import (harvest_source_create,
harvest_job_create,
harvest_job_create_all,)
from ckanext.harvest.logic.auth.update import (harvest_source_update,
harvest_objects_import,
harvest_jobs_run)
from ckanext.harvest.logic.auth.delete import (harvest_source_delete,)
return {
'harvest_source_show': harvest_source_show,
'harvest_source_list': harvest_source_list,
'harvest_job_show': harvest_job_show,
'harvest_job_list': harvest_job_list,
'harvest_object_show': harvest_object_show,
'harvest_object_list': harvest_object_list,
'harvesters_info_show': harvesters_info_show,
'harvest_source_create': harvest_source_create,
'harvest_job_create': harvest_job_create,
'harvest_job_create_all': harvest_job_create_all,
'harvest_source_update': harvest_source_update,
'harvest_source_delete': harvest_source_delete,
'harvest_objects_import': harvest_objects_import,
'harvest_jobs_run':harvest_jobs_run
}