Skip to content

Commit

Permalink
updated remote address checks to us x-forwarded-for
Browse files Browse the repository at this point in the history
  • Loading branch information
Sasha Cuerda committed Mar 3, 2018
1 parent 6d25e98 commit 6405a10
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 37 deletions.
1 change: 0 additions & 1 deletion ckanext/surrey/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ def resource_read(self, id, resource_id):
'''

result = super(SurreyPackageController, self).resource_read(id, resource_id)
log.debug('Called resource_read method')
if not record_is_viewable(c.pkg_dict, c.userobj):
base.abort(401, _('Unauthorized to read package %s') % id)
if not resource_is_viewable(c.pkg_dict, c.userobj):
Expand Down
33 changes: 18 additions & 15 deletions ckanext/surrey/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
from logging import getLogger
log = getLogger(__name__)


NotAuthorized = logic.NotAuthorized
NotFound = logic.NotFound


# Our custom template helper function.
def format_date(date):
'''Take timestamp and return a formatted date Month, day Year.'''
"""Take timestamp and return a formatted date Month, day Year."""
try:
mytime = time.strptime(date[:10], "%Y-%m-%d")
except:
Expand All @@ -25,10 +25,12 @@ def format_date(date):
# Just return some example text.
return output


def update_frequency():
frequency_list = (u"Yearly", u"Monthly", u"Weekly", u"Daily", u"Realtime", u"Punctual", u"Variable", u"Never")
return frequency_list


def city_departments():
department_list = (
u"City Manager", u"Engineering", u"Finance & Technology", u"Human Resources",
Expand All @@ -37,12 +39,13 @@ def city_departments():
)
return department_list


def get_group_list():
groups = tk.get_action('group_list')(
data_dict={'all_fields': True})

return groups


def get_summary_list(num_packages):
list_without_summary = \
tk.get_action('package_search')(data_dict={'rows': num_packages, 'sort': 'metadata_modified desc'})['results']
Expand Down Expand Up @@ -100,16 +103,13 @@ def before_map(self, m):


class SurreyTemplatePlugin(plugins.SingletonPlugin, tk.DefaultDatasetForm):
'''An example that shows how to use the ITemplateHelpers plugin interface.
'''
"""An example that shows how to use the ITemplateHelpers plugin interface."""
plugins.implements(plugins.IConfigurer)
plugins.implements(plugins.IRoutes, inherit=True)
plugins.implements(plugins.ITemplateHelpers)
plugins.implements(plugins.IPackageController, inherit=True)
plugins.implements(plugins.IDatasetForm, inherit=False)


num_times_new_template_called = 0
num_times_read_template_called = 0
num_times_edit_template_called = 0
Expand Down Expand Up @@ -351,7 +351,6 @@ def before_map(self, map):
m.connect('dataset read', '/{id}', action='read', ckan_icon='sitemap')
m.connect('resources', '/resources/{id}', action='resources')


with SubMapper(map, controller=api_controller, path_prefix='/api{ver:/1|/2|/3|}', ver='/3') as m:
m.connect('/action/package_list', action='restricted_package_list', conditions=GET)
m.connect('/action/current_package_list_with_resources', action='restricted_package_list_with_resources', conditions=GET)
Expand All @@ -362,10 +361,10 @@ def after_map(self, map):
return map

def before_search(self, search_params):
'''
"""
Customizes package search and applies filters based on the dataset metadata-visibility
and user roles.
'''
"""

# Change the default sort order when no query passed
if not search_params.get('q') and search_params.get('sort') in (None, 'rank'):
Expand All @@ -390,10 +389,12 @@ def before_search(self, search_params):

try:
user_name = c.user or 'visitor'
white_listed = check_if_whitelisted(c.remote_addr)
remote_addr = request.environ.get(u'HTTP_X_FORWARDED_FOR', u'')
remote_addr = remote_addr if remote_addr else c.remote_addr
white_listed = check_if_whitelisted(remote_addr) or check_if_whitelisted(c.remote_addr)

# There are no restrictions for sysadmin
if (c.userobj and c.userobj.sysadmin == True) or white_listed:
if (c.userobj and c.userobj.sysadmin is True) or white_listed:
fq += ' '
else:
fq += ' -metadata_visibility:("Private")'
Expand Down Expand Up @@ -427,7 +428,9 @@ def after_search(self, search_results, search_params):
return search_results

def before_view(self, pkg_dict):
if check_if_whitelisted(c.remote_addr): # Whitelist set via CKAN admin config panel
remote_addr = request.environ.get(u'HTTP_X_FORWARDED_FOR', u'')
remote_addr = remote_addr if remote_addr else c.remote_addr
if check_if_whitelisted(remote_addr) or check_if_whitelisted(c.remote_addr):
return pkg_dict

if not record_is_viewable(pkg_dict, c.userobj):
Expand All @@ -436,10 +439,10 @@ def before_view(self, pkg_dict):
return pkg_dict

def before_index(self, pkg_dict):
'''
"""
Makes the sort by name case insensitive.
Note that the search index must be rebuild for the first time in order for the changes to take affect.
'''
"""
title = pkg_dict['title']
if title:
# Assign title to title_string with all characters switched to lower case.
Expand Down
46 changes: 25 additions & 21 deletions ckanext/surrey/util/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from logging import getLogger
import ckan.model as model
import ckan.plugins.toolkit as toolkit
from ckan.common import c
from ckan.common import c, request
import pylons.config as config
from ckan.lib.base import _
from IPy import IP
Expand All @@ -22,9 +22,9 @@ def get_whitelist_settings():


def check_if_whitelisted(remote_addr):
'''Load white list from settings. Returns true if settings are missing.'''
"""Load white list from settings. Returns true if settings are missing."""
white_list_settings = get_whitelist_settings()
# log.info(white_list_settings)
log.info(white_list_settings)
if white_list_settings:
surrey_white_list = [IP(wl) for wl in white_list_settings]
for white_list in surrey_white_list:
Expand All @@ -35,10 +35,10 @@ def check_if_whitelisted(remote_addr):


def get_package_extras_by_key(pkg_extra_key, pkg_dict):
'''
"""
Gets the specified `extras` field by pkg_extra_key, if it exists
Returns False otherwise
'''
"""
if 'extras' in pkg_dict:
try:
pkg_extras = pkg_dict.extras
Expand Down Expand Up @@ -107,9 +107,9 @@ def get_package_owner_org(pkg):


def get_username(id):
'''
"""
Returns the user name for the given id.
'''
"""

try:
user = toolkit.get_action('user_show')(data_dict={'id': id})
Expand All @@ -119,30 +119,30 @@ def get_username(id):


def get_orgs_user_can_edit(userobj):
'''
"""
Returns the list of id's of organizations that the current logged in user
can edit. The user must have an admin or editor role in the organization.
'''
"""

if not userobj:
return []

'''
"""
context = {'model': model, 'session': model.Session,
'user': c.user or c.author, 'auth_user_obj': c.userobj}
perm_dict = {'permission' : 'create_dataset'}
orgs = toolkit.get_action('organization_list_for_user')(data_dict=perm_dict)
orgs = [org['id'] for org in orgs]
'''
"""
orgs = userobj.get_group_ids('organization', 'editor') + c.userobj.get_group_ids('organization', 'admin')
return orgs


def get_user_orgs(user_id, role=None):
'''
"""
Returns the list of orgs and suborgs that the given user belongs to and has the given role('admin', 'member', 'editor', ...)
'''
"""

member_query = model.Session.query(model.Member.group_id.label('id')) \
.filter(model.Member.table_name == 'user') \
Expand All @@ -158,20 +158,23 @@ def get_user_orgs(user_id, role=None):


def record_is_viewable(pkg_dict, userobj):
'''
"""
Checks if the user is authorized to view the dataset.
Public users can only see published or pending archive records and only if the metadata-visibility is public.
Government users who are not admins or editors can only see the published or pending archive records.
Editors and admins can see all the records of their organizations in addition to what government users can see.
'''
"""

# Internal users can access all records
if check_if_whitelisted(c.remote_addr):
remote_addr = request.environ.get(u'HTTP_X_FORWARDED_FOR', u'')
remote_addr = remote_addr if remote_addr else c.remote_addr
white_listed = check_if_whitelisted(remote_addr) or check_if_whitelisted(c.remote_addr)
if white_listed:
log.info('Access granted. %s is on white list' % c.remote_addr)
return True

# Sysadmin can view all records
if userobj and userobj.sysadmin == True:
if userobj and userobj.sysadmin is True:
return True

metadata_visibility = get_package_metadata_visibility(pkg_dict)
Expand All @@ -193,7 +196,6 @@ def record_is_viewable(pkg_dict, userobj):

if userobj:
user_orgs = get_orgs_user_can_edit(userobj)

if owner_org in user_orgs:
return True

Expand All @@ -202,13 +204,16 @@ def record_is_viewable(pkg_dict, userobj):

def resource_is_viewable(pkg_dict, userobj):
# Internal users have universal access
if check_if_whitelisted(c.remote_addr):
remote_addr = request.environ.get(u'HTTP_X_FORWARDED_FOR', u'')
remote_addr = remote_addr if remote_addr else c.remote_addr
white_listed = check_if_whitelisted(remote_addr) or check_if_whitelisted(c.remote_addr)
if white_listed:
log.info('Access granted. %s is on white list' % c.remote_addr)
return True

# We need to check the record status to handle the case where the record is private but the resource is private
# This should be handled at the metadata save validation, but for now, this works.
if record_is_viewable(pkg_dict, userobj) == False:
if record_is_viewable(pkg_dict, userobj) is False:
return False

# Sysadmin can view all records
Expand All @@ -230,7 +235,6 @@ def resource_is_viewable(pkg_dict, userobj):

if userobj:
user_orgs = get_orgs_user_can_edit(userobj)

if owner_org in user_orgs:
return True

Expand Down

0 comments on commit 6405a10

Please sign in to comment.