source: TI05-delivery/ows_framework/trunk/ows_server/ows_server/lib/base.py @ 2934

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI05-delivery/ows_framework/trunk/ows_server/ows_server/lib/base.py@2934
Revision 2934, 7.6 KB checked in by pjkersha, 13 years ago (diff)

Added https capability for discovery login. Discovery service port is exposed outside with http and https viritual hosts. Login pages use the https virtual host.

ows_server/ndgDiscovery.config: added sslServer param for NDG_SECURITY section - needed for running discovery login over https

ows_server/ows_server/controllers/login.py:

  • LogController?.wayf for efficiency use single call to new Attribute Authority getAllHostsInfo() rather than consecutive calls to getHostInfo() and getAllHostsInfo() as before
  • LoginController?.doRedirect makes a check on the return to address by checking the peer's SSL certificate against a list of accepted DNs returned from Attribute Authority getAllHostsInfo()

ows_server/ows_server/lib/base.py:

Line 
1import urllib
2from urlparse import urlsplit, urlunsplit
3from base64 import urlsafe_b64encode
4from pylons import Response, c, g, cache, request, session
5from pylons.controllers import WSGIController
6from pylons.decorators import jsonify, validate
7from pylons.templating import render, render_response
8from pylons.helpers import abort, redirect_to, etag_cache
9from pylons.i18n import N_, _, ungettext
10from paste.request import construct_url
11import ows_server.models as model
12import ows_server.lib.helpers as h
13from ows_server.lib.security_util import setSecuritySession, LoginServiceQuery
14from ows_common import exceptions as OWS_E
15from ows_common.operations_metadata import OperationsMetadata, Operation, RequestMethod
16from ows_common.get_capabilities import ServiceMetadata
17import ows_common.xml
18
19
20try:
21    from xml.etree import ElementTree as ET
22except ImportError:
23    from elementtree import ElementTree as ET
24
25import logging
26logger = logging.getLogger(__name__)
27
28# Configure
29EXCEPTION_TYPE = request.environ['ndgConfig'].get('OWS_SERVER', 'exception_type', 'ogc').lower()
30
31
32
33class BaseController(WSGIController):
34   
35    def __call__(self, environ, start_response):       
36        # Insert any code to be run per request here. The Routes match
37        # is under environ['pylons.routes_dict'] should you want to check
38        # the action or route vars here
39
40        logger.debug("BaseController.__call__ ...")
41       
42        # construct URL picking up setting of server name from config to
43        # avoid exposing absolute URL hidden behind mod_proxy see #857           
44        c.requestURL = g.server + urllib.quote(environ.get('PATH_INFO', ''))
45
46        query = '&'.join(["%s=%s" % item for item in request.params.items()])
47        if query:
48            c.requestURL += '?' + query
49
50        logger.debug("BaseController.__call__ URL = [%s]" % c.requestURL)
51
52        # Base 64 encode to enable passing around in 'r' argument of query
53        # string for use with login/logout
54        c.b64encRequestURL = urlsafe_b64encode(c.requestURL)
55
56        if 'h' in request.params:
57            # 'h' corresponds to the setting of a session manager host i.e.
58            # the request has come from a completed login from the login
59            # service
60            logger.debug("Setting security session from URL query args ...")
61           
62            # Copy the query arguments into security session keys
63            setSecuritySession()
64           
65            if 'panelView' not in session:
66                session['panelView']='History'
67            session.save()
68           
69            # Re-construct the URL removing the security related arguments
70            qs = LoginServiceQuery.stripFromURI()
71
72            logger.debug('Switching from https to http...')
73            cc = g.server + urllib.quote(environ.get('PATH_INFO',''))
74            if qs:
75                cc += "?" + qs
76               
77            logger.debug('URL transport switched to http: "%s"' % cc)
78            h.redirect_to(cc)
79
80               
81        #organise the information needed by pagetabs ...
82        # TODO avoid this for the server controllers ...
83       
84        c.pageTabs=[('Search',g.discoveryURL)]
85        if 'results' in session: c.pageTabs.append(('Results',session['results']))
86        if 'lastViewed' in session: c.pageTabs.append(('Display',session['lastViewed']))
87       
88        if 'selection' in session:
89            c.pageTabs.append(('Selections',h.url_for(controller='selection',action='index')))
90            c.pageTabs.append(('Visualise',h.url_for(controller='visualise', action='index')))
91            c.pageTabs.append(('Download','Blah'))
92
93        return WSGIController.__call__(self, environ, start_response)
94   
95class OwsController(BaseController):
96    def __call__(self, environ, start_response):
97
98        # All OWS parameter names are case insensitive.
99        req = request._current_obj()
100        self.ows_params = {}
101        for k in req.params:
102            self.ows_params[k.lower()] = req.params[k]       
103
104        # If the EXCEPTION_TYPE is 'pylons' let Pylons catch any exceptions.
105        # Otherwise send an OGC exception report for any OWS_E.OwsError
106        if 'pylons' in EXCEPTION_TYPE:
107            self._fixOwsAction(environ)
108            return super(OwsController, self).__call__(environ, start_response)
109        else:
110            try:
111                self._fixOwsAction(environ)
112                return super(OwsController, self).__call__(environ, start_response)
113            except OWS_E.OwsError, e:
114                logger.exception(e)
115
116                r=render_response('exception_report', report=e.report, format='xml')
117                r.headers['content-type'] = 'text/xml'
118                return r
119
120
121    def _fixOwsAction(self, environ):
122        # Override the Routes action from the request query parameter
123        try:
124            action = self.ows_params['request']
125        except KeyError:
126            raise OWS_E.MissingParameterValue('REQUEST parameter not specified', 'REQUEST')
127
128        # Check action is a method in self
129        if not getattr(self, action):
130            raise OWS_E.InvalidParameterValue('request=%s not supported' % action, 'REQUEST')
131
132        # override routes action with request
133        environ['pylons.routes_dict']['action'] = action
134        del self.ows_params['request']
135
136    def _loadCapabilities(self):
137        """
138        creates an ows_common.get_capabilities.ServiceMetadata object
139        by consulting the paste configuration and annotations in the
140        controller definition.
141
142        """
143        # Deduce ows_endpoint from routes
144        ows_endpoint = h.url_for(controller=request.environ['pylons.routes_dict']['controller'])
145       
146        #Deduce base_url from config
147        base_url =request.environ['ndgConfig'].get('DEFAULT','server')
148
149       
150        # Get the server-level configuration data from an XML file
151        config = request.environ['paste.config']
152        sm_tree = ET.parse(config['ows_common_config'])
153        sm = ows_common.xml.service_metadata(sm_tree.getroot())
154       
155        # Extract service-level parameters and constraint
156        parameters = getattr(self, '_ows_parameters', {})
157        constraints = getattr(self, '_ows_constraints', {})
158        versions = getattr(self, '_ows_versions', [])
159       
160        # Extract operation-level parameters and constraints
161        od = {}
162        for attr in dir(self):
163            op = getattr(self, attr)
164            if hasattr(op, '_ows_name'):
165                p = getattr(op, '_ows_parameters', {})
166                c = getattr(op, '_ows_constraints', {})
167                od[op._ows_name] = Operation(get=RequestMethod(href=base_url+ows_endpoint),
168                                             post=None,
169                                             parameters=p,
170                                             constraints=c,
171                                             name=op._ows_name)
172       
173        sm.operationsMetadata = OperationsMetadata(od, constraints, parameters)
174        sm.serviceIdentification.serviceTypeVersions = versions
175        return sm
176
177    def _renderCapabilities(self, template='ows/get_capabilities'):
178        """
179        The standard way of returning a Capabilities document.
180
181        Each subclass should implement self._load_capabilities() and call
182        this method to return a response object.
183
184        """
185        c.service_metadata = self._loadCapabilities()       
186        r = render_response(template, format='xml')
187        r.headers['content-type'] = 'text/xml'
188        return r
189
190
191# Include the '_' function in the public names
192__all__ = [__name for __name in locals().keys() if not __name.startswith('_') \
193           or __name == '_']
Note: See TracBrowser for help on using the repository browser.