source: TI05-delivery/ows_framework/trunk/ows_server/ows_server/lib/security_util.py @ 2959

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

ows_server/ows_server/controllers/login.py:

  • removed call - BaseController?.call supplies all the needed functionality
  • added to before - filter out getCredentials from return to address - getCredentials can contain cred args so should be removed. The code here is a 2nd line of defence - BaseController?.call removes getCredentials from request URLs so return to should nvere get assigned a getCredenials call.

ows_server/ows_server/controllers/logout.py:

  • same mod to before call as login.py listed above.

ows_server/ows_server/lib/security_util.py:

  • constructURL function - not used but a starting point for attempting to encapsulate security related code and remove it from BaseController?.call

ows_server/ows_server/lib/base.py:

  • if c.requestURL contains getCredentials filter it out and redirect to /discovery instead. getCredentials recives username/password from login form. Without this check these fields can be exposed as URL query args in a c.returnTo address(!)
Line 
1# Copyright (C) 2007 STFC & NERC (Science and Technology Facilities Council).
2# This software may be distributed under the terms of the
3# Q Public License, version 1.0 or later.
4# http://ndg.nerc.ac.uk/public_docs/QPublic_license.txt
5"""
6Utilities for transfor of credentials over login service
7
8@author: Philip Kershaw
9"""
10__revision__ = '$Id:$'
11
12import logging
13log = logging.getLogger(__name__)
14
15import urllib
16from pylons import session, request, g
17
18
19class SecuritySession(object):
20    """Utility for Pylons security session keys enables correct
21    keys to be set
22   
23    @type key: string
24    @cvar key: name of security key in session object
25   
26    @type subKeys: tuple
27    @cvar subKeys: list of valid security keys to set"""
28   
29    key = 'ndgSec'
30    subKeys = ('h', 'sid', 'u', 'roles')
31
32    def __init__(self, **subKeys):
33        """Update the security key of session object with the
34        input sub keys
35       
36        type **subKeys: dict
37        param **subKeys: set any of the security keywords as contained in
38        SecuritySession.subKeys"""
39       
40        # Set the security session keys from request.params if no keywords
41        # were input
42        if subKeys == {}:
43            subKeys = LoginServiceQuery.decodeRequestParams()
44           
45        # Ensure security key is present
46        if SecuritySession.key not in session:
47            session[SecuritySession.key] = {}
48         
49        # Ensure valid keys are being set   
50        for k in subKeys:
51            if k not in SecuritySession.subKeys:
52                raise KeyError, 'Invalid key Security session dict: "%s"' % k
53       
54        # Update security values
55        session[SecuritySession.key].update(subKeys)           
56        session.save()
57        log.debug("Set security session: %s" % session[SecuritySession.key])
58
59    @classmethod
60    def delete(self):
61        """Delete security key from session object"""
62        if SecuritySession.key in session:
63            del session[SecuritySession.key]
64            session.save()
65        log.debug("Deleted security key to session object: %s" % session)
66           
67setSecuritySession = SecuritySession
68           
69 
70class LoginServiceQuery(object):
71    """Create query string containing security credentials.  This is used by
72    the Identity Provider pass the credentials over a HTTP GET back to the
73    Service Provider
74   
75    @cvar keys: query args to be copied into security session dict
76    @type keys: tuple
77    @cvar roleSep: delimit roles names in URL arg with this symbol
78    @type roleSep: string
79    @cvar argSep: standard arg separator for URLs
80    @type argSep: string"""
81   
82    keys = SecuritySession.subKeys
83    rolesSep = ","
84    argSep = "&"
85       
86    def __str__(self):
87        """Provide convenient short-cut for call to make query string
88
89        @rtype: string
90        @return: URL query string with security args"""
91        return self.makeQueryStr()
92   
93    @classmethod
94    def makeQueryStr(cls):
95        """Create the query string containing the required security
96        credentials to return to the service provider
97       
98        @rtype: string
99        @return: URL query string with security args"""
100       
101        # Make a copy of the security session dict reseting the
102        # roles to a single string ready for passing over URL
103        secDict = session[SecuritySession.key].copy()
104        secDict['roles'] = cls.rolesSep.join(secDict['roles'])
105       
106        # Return the full query as a string
107        return cls.argSep.join(["%s=%s" % (k, secDict[k]) for k in cls.keys])
108
109    @classmethod
110    def stripFromURI(cls, *params):
111        """Make a new query string using Pylons request.params but stripping
112        args relating to security
113       
114        @param params: parameters to remove instead of those contained in keys
115        class variable
116        @type additionalParams: tuple
117        @rtype: string
118        @return: URL query string with security args removed"""
119        keys = params or cls.keys
120        return cls.argSep.join(['%s=%s' % (i, request.params[i]) \
121                                for i in request.params if i not in keys])
122
123    @classmethod
124    def decodeRequestParams(cls):
125        """Get security parameters from request.params received from Login
126        Service (IdP).  Decode parameters where necessary: roles are sent as a
127        comma delimited list - convert into a list type
128       
129        @rtype: dict
130        @return: dictionary of security parameters
131        """
132       
133        try:
134            # request.params is actually a MultiDict type but for the purposes
135            # of this code it can be treated as a regular dict type
136            keys = dict([(k, request.params[k]) for k in cls.keys])
137        except KeyError, e:
138            OwsError, \
139                '%s argument is missing from URL returned by Login Service' %\
140                str(e)
141               
142        # Modify roles from a comma delimited string into a list
143        if 'roles' in keys:
144            keys['roles'] = keys['roles'].split(cls.rolesSep)
145
146        return keys
147
148# TODO: this could be used in the future to replace parts of BaseController.
149# __call__ but leave for the moment as there may be a more modular solution
150def constructURL(pathInfo,
151                 scheme=None,
152                 netloc=None,
153                 altPathInfo='/discovery',
154                 query=None):
155    """Utility for BaseController.  Remove getCredentials calls"""
156 
157    if scheme is None and netloc is None:
158        pathPfx = g.server
159    else:
160        pathPfx = urlunsplit((scheme, netloc, '', '', ''))
161       
162    if 'getCredentials' in pathInfo:
163        logger.debug("Reverting request URL from getCredentials to discovery...")
164        requestURL = pathPfx + altPathInfo       
165    else:
166        requestURL = pathPfx + pathInfo
167        if query is None:
168            query='&'.join(["%s=%s"%item for item in request.params.items()])
169
170        if query:
171            requestURL += '?' + query
172           
173    return requestURL
174
175
176import sys
177
178class SecurityConfigError(Exception):
179    """Handle errors from parsing security config items"""
180       
181class SecurityConfig(object):
182    """Get Security related parameters from the Pylons NDG config file"""
183
184    def __init__(self, cfg=None):
185        '''Get PKI settings for Attribute Authority and Session Manager from
186        the configuration file
187       
188        @type param: pylons config file object
189        @param cfg: reference to NDG configuration file.  If omitted defaults
190        to request.environ['ndgConfig']'''
191       
192        if cfg is None:
193            cfg = request.environ['ndgConfig']
194
195        tracefileExpr = cfg.get('NDG_SECURITY', 'tracefile')
196        if tracefileExpr:
197            self.tracefile = eval(tracefileExpr)
198
199        self.smURI = cfg.get('NDG_SECURITY', 'sessionMgrURI')       
200        self.aaURI = cfg.get('NDG_SECURITY', 'attAuthorityURI')
201       
202        # ... for SSL connections to security web services
203        try:
204            self.sslCACertFilePathList = \
205            cfg.get('NDG_SECURITY', 'sslCACertFilePathList').split()
206               
207        except AttributeError:
208            raise SecurityConfigError, \
209                        'No "sslCACertFilePathList" security setting'
210
211        self.sslPeerCertCN = cfg.get('NDG_SECURITY', 'sslPeerCertCN')
212
213        # ...and for WS-Security digital signature
214        self.wssCertFilePath = cfg.get('NDG_SECURITY', 'wssCertFilePath')
215        self.wssPriKeyFilePath = cfg.get('NDG_SECURITY', 'wssKeyFilePath')
216        self.wssPriKeyPwd = cfg.get('NDG_SECURITY', 'wssKeyPwd')
217
218        try:
219            self.wssCACertFilePathList = \
220                cfg.get('NDG_SECURITY', 'wssCACertFilePathList').split()
221               
222        except AttributeError:
223            raise SecurityConfigError, \
224                                'No "wssCACertFilePathList" security setting'
225
226        # Gatekeeper params
227       
228        # Attribute Certificate Issuer
229        self.acIssuer = cfg.get('NDG_SECURITY', 'acIssuer')
230       
231        # verification of X.509 cert back to CA
232        self.acCACertFilePathList = cfg.get('NDG_SECURITY', 
233                                            'acCACertFilePathList')
234
235             
236    def __repr__(self):
237        return '\n'.join(["%s=%s" % (k,v) for k,v in self.__dict__.items() \
238                if k[:2] != "__"])
Note: See TracBrowser for help on using the repository browser.