-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #82 from Ouranosinc/magpie_adapter
Magpie adapter
- Loading branch information
Showing
11 changed files
with
239 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,6 @@ | |
""" | ||
|
||
|
||
__version__ = '0.6.1' | ||
__version__ = '0.6.2' | ||
__author__ = "Francois-Xavier Derue, Francis Charette-Migneault" | ||
__email__ = '[email protected]' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
from magpie.definitions.pyramid_definitions import * | ||
from magpie.definitions.ziggurat_definitions import * | ||
from magpie.definitions.twitcher_definitions import * | ||
from magpie.adapter.magpieowssecurity import * | ||
from magpie.adapter.magpieservice import * | ||
from magpie.models import get_user | ||
from magpie.security import auth_config_from_settings | ||
from magpie.db import * | ||
import logging | ||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class MagpieAdapter(AdapterInterface): | ||
|
||
def servicestore_factory(self, registry, database=None): | ||
return MagpieServiceStore(registry=registry) | ||
|
||
def owssecurity_factory(self, registry): | ||
return MagpieOWSSecurity() | ||
|
||
def configurator_factory(self, settings): | ||
# Disable rpcinterface which is conflicting with postgres db | ||
settings['twitcher.rpcinterface'] = False | ||
|
||
logger.info('Loading MagpieAdapter config') | ||
config = auth_config_from_settings(settings) | ||
config.set_request_property(get_user, 'user', reify=True) | ||
self.owsproxy_config(settings, config) | ||
return config | ||
|
||
def owsproxy_config(self, settings, config): | ||
logger.info('Loading MagpieAdapter owsproxy config') | ||
|
||
# use pyramid_tm to hook the transaction lifecycle to the request | ||
config.include('pyramid_tm') | ||
|
||
session_factory = get_session_factory(get_engine(settings)) | ||
config.registry['dbsession_factory'] = session_factory | ||
|
||
# make request.db available for use in Pyramid | ||
config.add_request_method( | ||
# r.tm is the transaction manager used by pyramid_tm | ||
lambda r: get_tm_session(session_factory, r.tm), | ||
'db', | ||
reify=True | ||
) | ||
|
||
logger.info('Adding MagpieAdapter owsproxy routes and views') | ||
protected_path = settings.get('twitcher.ows_proxy_protected_path', '/ows') | ||
config.add_route('owsproxy', protected_path + '/{service_name}') | ||
config.add_route('owsproxy_extra', protected_path + '/{service_name}/{extra_path:.*}') | ||
config.add_route('owsproxy_secured', protected_path + '/{service_name}/{access_token}') | ||
|
||
config.add_view(owsproxy, route_name='owsproxy') | ||
config.add_view(owsproxy, route_name='owsproxy_extra') | ||
config.add_view(owsproxy, route_name='owsproxy_secured') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import tempfile | ||
from magpie.definitions.twitcher_definitions import * | ||
from magpie.definitions.pyramid_definitions import * | ||
from magpie.services import service_factory | ||
from magpie.models import Service | ||
from magpie.api.api_except import evaluate_call, verify_param | ||
|
||
import logging | ||
LOGGER = logging.getLogger("TWITCHER") | ||
|
||
|
||
class MagpieOWSSecurity(object): | ||
|
||
def prepare_headers(self, request, access_token): | ||
if "esgf_access_token" in access_token.data or "esgf_credentials" in access_token.data: | ||
workdir = tempfile.mkdtemp(prefix=request.prefix, dir=request.workdir) | ||
if fetch_certificate(workdir=workdir, data=access_token.data): | ||
request.headers['X-Requested-Workdir'] = workdir | ||
request.headers['X-X509-User-Proxy'] = workdir + '/' + ESGF_CREDENTIALS | ||
LOGGER.debug("Prepared request headers.") | ||
return request | ||
|
||
def check_request(self, request): | ||
twitcher_protected_path = request.registry.settings.get('twitcher.ows_proxy_protected_path', '/ows') | ||
if request.path.startswith(twitcher_protected_path): | ||
service_name = parse_service_name(request.path, twitcher_protected_path) | ||
service = evaluate_call(lambda: Service.by_service_name(service_name, db_session=request.db), | ||
fallback=lambda: request.db.rollback(), | ||
httpError=HTTPForbidden, msgOnFail="Service query by name refused by db") | ||
verify_param(service, notNone=True, httpError=HTTPNotFound, msgOnFail="Service name not found in db") | ||
|
||
# return a specific type of service, ex: ServiceWPS with all the acl (loaded according to the service_type) | ||
service_specific = service_factory(service, request) | ||
# should contain all the acl, this the only thing important | ||
# parse request (GET/POST) to get the permission requested for that service | ||
permission_requested = service_specific.permission_requested() | ||
|
||
if permission_requested: | ||
authn_policy = request.registry.queryUtility(IAuthenticationPolicy) | ||
authz_policy = request.registry.queryUtility(IAuthorizationPolicy) | ||
principals = authn_policy.effective_principals(request) | ||
has_permission = authz_policy.permits(service_specific, principals, permission_requested) | ||
if not has_permission: | ||
raise OWSAccessForbidden("Not authorized to access this resource.") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
""" | ||
Store adapters to read data from magpie. | ||
""" | ||
|
||
import logging | ||
import requests | ||
import json | ||
LOGGER = logging.getLogger(__name__) | ||
|
||
from magpie.definitions.twitcher_definitions import * | ||
from magpie.definitions.pyramid_definitions import ConfigurationError | ||
|
||
|
||
class MagpieServiceStore(ServiceStore): | ||
""" | ||
Registry for OWS services. Uses magpie to fetch service url and attributes. | ||
""" | ||
def __init__(self, registry): | ||
try: | ||
self.magpie_url = registry.settings.get('magpie.url').strip('/') | ||
except AttributeError: | ||
#If magpie.url does not exist, calling strip fct over None will raise this issue | ||
raise ConfigurationError('magpie.url config cannot be found') | ||
|
||
def save_service(self, service, overwrite=True, request=None): | ||
""" | ||
Magpie store is read-only, use magpie api to add services | ||
""" | ||
raise NotImplementedError | ||
|
||
def delete_service(self, name, request=None): | ||
""" | ||
Magpie store is read-only, use magpie api to delete services | ||
""" | ||
raise NotImplementedError | ||
|
||
#TODO Now only wps are returned as well as fetch_by_ulr... fetch_by_name has been patched to support other service_type | ||
def list_services(self, request=None): | ||
""" | ||
Lists all services registered in magpie. | ||
""" | ||
my_services = [] | ||
response = requests.get('{url}/services/types/wps'.format(url=self.magpie_url), | ||
cookies=request.cookies) | ||
if response.status_code != 200: | ||
raise response.raise_for_status() | ||
services = json.loads(response.text) | ||
if 'wps' in services['services']: | ||
for key, service in services['services']['wps'].items(): | ||
my_services.append(Service(url=service['service_url'], | ||
name=service['service_name'], | ||
type=service['service_type'])) | ||
return my_services | ||
|
||
def fetch_by_name(self, name, request=None): | ||
""" | ||
Gets service for given ``name`` from magpie. | ||
""" | ||
response = requests.get('{url}/services/{name}'.format(url=self.magpie_url, name=name), | ||
cookies=request.cookies) | ||
if response.status_code == 404: | ||
raise ServiceNotFound | ||
if response.status_code != 200: | ||
raise response.raise_for_status() | ||
services = json.loads(response.text) | ||
if name in services: | ||
return Service(url=services[name]['service_url'], | ||
name=services[name]['service_name'], | ||
type=services[name]['service_type']) | ||
raise ServiceNotFound | ||
|
||
def fetch_by_url(self, url, request=None): | ||
""" | ||
Gets service for given ``url`` from mongodb storage. | ||
""" | ||
services = self.list_services(request=request) | ||
for service in services: | ||
if service.url == url: | ||
return service | ||
raise ServiceNotFound | ||
|
||
|
||
def clear_services(self, request=None): | ||
""" | ||
Magpie store is read-only, use magpie api to delete services | ||
""" | ||
raise NotImplementedError |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from twitcher.adapter.base import AdapterInterface | ||
from twitcher.owsproxy import owsproxy | ||
from twitcher.owsexceptions import OWSAccessForbidden | ||
from twitcher.utils import parse_service_name | ||
from twitcher.esgf import fetch_certificate, ESGF_CREDENTIALS | ||
from twitcher.datatype import Service | ||
from twitcher.store.base import ServiceStore | ||
from twitcher.exceptions import ServiceNotFound |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters