Changeset 4838
- Timestamp:
- 19/01/09 12:00:54 (12 years ago)
- Location:
- TI12-security/trunk
- Files:
-
- 6 added
- 12 edited
Legend:
- Unmodified
- Added
- Removed
-
TI12-security/trunk/python/MyProxyClient/myproxy/__init__.py
r4770 r4838 7 7 __date__ = "15/12/08" 8 8 __copyright__ = "(C) 2009 Science and Technology Facilities Council" 9 __license__ = """ LGPL"""9 __license__ = """BSD""" 10 10 __contact__ = "Philip.Kershaw@stfc.ac.uk" 11 11 __revision__ = '$Id$' -
TI12-security/trunk/python/MyProxyClient/myproxy/client.py
r4770 r4838 11 11 __date__ = "02/06/05" 12 12 __copyright__ = "(C) 2009 Science and Technology Facilities Council" 13 __license__ = """ LGPL13 __license__ = """BSD 14 14 15 15 For myproxy_logon see Access Grid Toolkit Public License (AGTPL) -
TI12-security/trunk/python/MyProxyClient/myproxy/utils/__init__.py
r4770 r4838 7 7 __date__ = "15/12/08" 8 8 __copyright__ = "(C) 2009 Science and Technology Facilities Council" 9 __license__ = """ LGPL"""9 __license__ = """BSD""" 10 10 __contact__ = "Philip.Kershaw@stfc.ac.uk" 11 11 __revision__ = '$Id$' -
TI12-security/trunk/python/MyProxyClient/myproxy/utils/openssl.py
r4770 r4838 7 7 __date__ = "08/02/07" 8 8 __copyright__ = "(C) 2009 Science and Technology Facilities Council" 9 __license__ = """ LGPL"""9 __license__ = """BSD""" 10 10 __contact__ = "Philip.Kershaw@stfc.ac.uk" 11 11 __revision__ = '$Id:openssl.py 4643 2008-12-15 14:53:53Z pjkersha $' -
TI12-security/trunk/python/MyProxyClient/setup.py
r4770 r4838 7 7 __date__ = "12/12/08" 8 8 __copyright__ = "(C) 2009 Science and Technology Facilities Council" 9 __license__ = """ LGPL9 __license__ = """BSD 10 10 11 11 Software adapted from myproxy_logon. - For myproxy_logon see Access Grid … … 52 52 'Intended Audience :: System Administrators', 53 53 'Intended Audience :: Science/Research', 54 'License :: OSI Approved :: GNU Library or Lesser General Public License ( LGPL)',54 'License :: OSI Approved :: GNU Library or Lesser General Public License (BSD)', 55 55 'Natural Language :: English', 56 56 'Operating System :: Microsoft :: Windows', -
TI12-security/trunk/python/MyProxyClient/test/__init__.py
r4770 r4838 6 6 __date__ = "13/12/08" 7 7 __copyright__ = "(C) 2009 Science and Technology Facilities Council" 8 __license__ = """ LGPL"""8 __license__ = """BSD""" 9 9 __contact__ = "Philip.Kershaw@stfc.ac.uk" 10 10 __revision__ = '$Id$' -
TI12-security/trunk/python/MyProxyClient/test/test_myproxyclient.py
r4770 r4838 7 7 __date__ = "02/07/07" 8 8 __copyright__ = "(C) 2009 Science and Technology Facilities Council" 9 __license__ = """ LGPL"""9 __license__ = """BSD""" 10 10 __contact__ = "Philip.Kershaw@stfc.ac.uk" 11 11 __revision__ = '$Id$' -
TI12-security/trunk/python/ndg.security.common/ndg/security/common/X509.py
r4770 r4838 6 6 __date__ = "05/04/05" 7 7 __copyright__ = "(C) 2009 Science and Technology Facilities Council" 8 __license__ = \ 9 """This software may be distributed under the terms of the Q Public 10 License, version 1.0 or later.""" 8 __license__ = "BSD - See LICENSE file in the top-level directory" 11 9 __contact__ = "Philip.Kershaw@stfc.ac.uk" 12 10 __revision__ = '$Id$' … … 980 978 else: 981 979 return None 980 981 @classmethod 982 def Parse(cls, dn): 983 """Convenience method to create an X500DN object from a DN string 984 @type dn: basestring 985 @param dn: Distinguished Name 986 """ 987 return cls(dn=dn) 988 989 Deserialise = Deserialize = Parse -
TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/__init__.py
r4822 r4838 10 10 __contact__ = "Philip.Kershaw@stfc.ac.uk" 11 11 __revision__ = '$Id$' 12 import logging 13 log = logging.getLogger(__name__) 14 import httplib 12 15 13 16 class NDGSecurityMiddlewareBase(object): … … 15 18 propertyDefaults = {} 16 19 17 def __init__(self, app, app_conf, **local_conf): 18 pass 19 20 def __init__(self, app, app_conf, prefix='', **local_conf): 21 '''Set object attributes directly from app_conf and local_conf inputs 22 @type prefix: basestring 23 @param prefix: prefix for app_conf parameters e.g. 'ndgsecurity.' - 24 enables other global configuration parameters to be filtered out 25 ''' 26 self._app = app 27 opt = self.__class__.propertyDefaults.copy() 28 29 # If no prefix is set, there is no way to distinguish options set for 30 # this app and those applying to other applications 31 if app_conf is not None and prefix: 32 # Update from application config dictionary - filter using prefix 33 self.__class__._filterOpts(opt, app_conf, prefix=prefix) 34 35 # Similarly, filter keyword input 36 self.__class__._filterOpts(opt, local_conf, prefix=prefix) 37 38 # Update options from keywords - matching app_conf ones will be 39 # overwritten 40 opt.update(local_conf) 41 42 # Set options as object attributes 43 for name, val in opt.items(): 44 if not name.startswith('_'): 45 setattr(self, name, val) 46 47 def _setResponse(self, 48 environ, 49 start_response, 50 notFoundMsg=None, 51 notFoundMsgContentType=None): 52 if self._app: 53 return self._app(environ, start_response) 54 else: 55 return self._setErrorResponse(environ, 56 start_response, 57 msg=notFoundMsg, 58 code=404, 59 contentType=notFoundMsgContentType) 60 61 def _setErrorResponse(self, environ, start_response, msg=None, code=500, 62 contentType=None): 63 '''Convenience method to set a simple error response 64 65 @type environ: dict 66 @param environ: standard WSGI environ parameter 67 @type start_response: builtin_function_or_method 68 @param start_response: standard WSGI callable to set the HTTP header 69 @type msg: basestring 70 @param msg: optional error message 71 @type code: int 72 @param code: standard HTTP error response code 73 @type contentType: basestring 74 @param contentType: set 'Content-type' HTTP header field - defaults to 75 'text/plain' 76 ''' 77 status = '%d %s' % (code, httplib.responses[code]) 78 if msg is None: 79 response = status 80 else: 81 response = msg 82 83 if contentType is None: 84 contentType = 'text/plain' 85 86 start_response(status, 87 [('Content-type', contentType), 88 ('Content-Length', str(len(response)))]) 89 return response 90 20 91 # Utility functions to support Paste Deploy application and filter function 21 92 # signatures … … 45 116 defOpt class variable 46 117 ''' 47 48 118 badOpt = [] 49 119 for k,v in newOpt.items(): … … 62 132 raise TypeError("Invalid input option(s) set: %s" % 63 133 (", ".join(badOpt))) 134 135 def setPathInfo(self, pathInfo=None, environ=None): 136 if pathInfo: 137 self._pathInfo = pathInfo 138 else: 139 if environ is None: 140 environ = self._environ 141 142 self._pathInfo = environ['PATH_INFO'] 143 144 def _getPathInfo(self): 145 return self._pathInfo 146 147 pathInfo = property(fget=_getPathInfo, 148 fset=setPathInfo, 149 doc="URL path as assigned to PATH_INFO environ key") 150 151 def _setEnviron(self, environ): 152 self._environ = environ 153 154 def _getEnviron(self): 155 return self._environ 156 157 environ = property(fget=_getEnviron, 158 fset=_setEnviron, 159 doc="Copy of WSGI environ dict") 160 161 162 class NDGSecurityPathFilter(NDGSecurityMiddlewareBase): 163 """Specialization of NDG Security Middleware to enable filtering based on 164 PATH_INFO""" 165 propertyDefaults = { 166 'errorResponseCode': 401, 167 'serverName': None, 168 'mountPath': '', 169 'pathMatchList': '/' 170 } 171 propertyDefaults.update(NDGSecurityMiddlewareBase.propertyDefaults) 172 173 _pathMatch = lambda self: self._pathInfo in self.pathMatchList 174 pathMatch = property(fget=_pathMatch, 175 doc="Check for input path match to list of paths" 176 "to which this middleware is to be applied") 177 178 def __init__(self, *arg, **kw): 179 super(NDGSecurityPathFilter, self).__init__(*arg, **kw) 180 self._pathMatchList = [] 181 182 def _getPathMatchList(self): 183 return self._pathMatchList 184 185 def _setPathMatchList(self, pathList): 186 ''' 187 @type pathList: list or tuple 188 @param pathList: list of URL paths to apply this middleware 189 to. Paths are relative to the point at which this middleware is mounted 190 as set in environ['PATH_INFO'] 191 ''' 192 # TODO: refactor to: 193 # * enable reading of path list from a database or some other 194 # configuration source. 195 # * enable some kind of pattern matching for paths 196 197 if isinstance(pathList, basestring): 198 # Try parsing a space separated list of file paths 199 self._pathMatchList = pathList.split() 200 201 elif not isinstance(pathList, (list, tuple)): 202 raise TypeError('Expecting a list or tuple for "pathMatchList"') 203 else: 204 self._pathMatchList = pathList 205 206 pathMatchList = property(fget=_getPathMatchList, 207 fset=_setPathMatchList, 208 doc='List of URL paths to which to apply SSL ' 209 'client authentication') 210 211 def _getErrorResponseCode(self): 212 """Error response code getter 213 @rtype: int 214 @return: HTTP error code set by this middleware on client cert. 215 verification error 216 """ 217 return self._errorResponseCode 218 219 def _setErrorResponseCode(self, code): 220 """Error response code setter 221 @type code: int or basestring 222 @param code: error response code set if client cert. verification 223 fails""" 224 if isinstance(code, int): 225 self._errorResponseCode = code 226 elif isinstance(code, basestring): 227 self._errorResponseCode = int(code) 228 else: 229 raise TypeError('Expecting int or string type for ' 230 '"errorResponseCode" attribute') 231 232 if self._errorResponseCode not in httplib.responses: 233 raise ValueError("Error response code [%d] is not recognised " 234 "standard HTTP response code" % 235 self._errorResponseCode) 236 237 errorResponseCode = property(fget=_getErrorResponseCode, 238 fset=_setErrorResponseCode, 239 doc="Response code raised if client " 240 "certificate verification fails") -
TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/pep/__init__.py
r4822 r4838 1 """WSGI Policy Enforcement P ackage1 """WSGI Policy Enforcement Point Package 2 2 3 3 NERC DataGrid Project … … 11 11 import logging 12 12 log = logging.getLogger(__name__) 13 import httplib 13 14 14 from ndg.security.server.wsgi import NDGSecurityMiddlewareBase 15 from ndg.security.server.wsgi import NDGSecurityPathFilter 16 from ndg.security.common.X509 import X500DN 15 17 16 18 17 class PEP(NDGSecurityMiddlewareBase): 18 def __init__(self, app, app_conf, **local_conf): 19 self._app = app 19 class PEPMiddleware(NDGSecurityPathFilter): 20 21 def __init__(self, *arg, **kw): 22 log.debug("Initialising PEPMiddleware ...") 23 super(PEPMiddleware, self).__init__(*arg, **kw) 24 self.charset = '; charset=utf-8' 20 25 21 26 def __call__(self, environ, start_response): 27 log.info("Calling PEP middleware ...") 28 self.environ = environ 29 self.setPathInfo() 30 log.error("environ=%s" % environ) 31 print >> environ['wsgi.errors'], "environ=%s" % environ 32 33 # TODO: Is a security session set? 34 35 # Is this requested URL secured? 36 if self.pathMatch: 37 return self._setErrorResponse(environ, 38 start_response, 39 code=self.errorResponseCode) 40 else: 41 # User is logged in - Redirect to HTTP based URL and complete 42 # Policy enforcement 43 response = self._redirectFromHTTPS2HTTP(start_response) 44 if response is not None: 45 return response 46 22 47 return self._setResponse(environ, start_response) 48 49 def _redirectFromHTTPS2HTTP(self, start_response): 50 sslServerDN = self.environ.get('SSL_SERVER_S_DN') 51 if sslServerDN is not None: 52 if self.serverName: 53 serverName = self.serverName 54 else: 55 dn = X500DN.Parse(sslServerDN) 56 serverName = dn['CN'] 57 58 url = 'http://' + serverName + self.mountPath + self.pathInfo 59 print >> self.environ['wsgi.errors'], "redirecting to [%s]" % url 60 return self._redirect(start_response, url) 23 61 24 def _setResponse(self,25 environ,26 start_response,27 notFoundMsg=None,28 notFoundMsgContentType=None):29 if self._app:30 return self._app(environ, start_response)31 else:32 return self._setErrorResponse(environ,33 start_response,34 msg=notFoundMsg,35 code=404,36 contentType=notFoundMsgContentType)37 38 def _setErrorResponse(self, environ, start_response, msg=None, code=500,39 contentType=None):40 '''Convenience method to set a simple error response41 62 42 @type environ: dict 43 @param environ: standard WSGI environ parameter 44 @type start_response: builtin_function_or_method 45 @param start_response: standard WSGI callable to set the HTTP header 46 @type msg: basestring 47 @param msg: optional error message 48 @type code: int 49 @param code: standard HTTP error response code 50 @type contentType: basestring 51 @param contentType: set 'Content-type' HTTP header field - defaults to 52 'text/plain' 53 ''' 54 status = '%d %s' % (code, httplib.responses[code]) 55 if msg is None: 56 response = status 57 else: 58 response = msg 63 def _redirect(self, start_response, url): 64 """Do a HTTP 302 redirect 59 65 60 if contentType is None: 61 contentType = 'text/plain' 62 63 start_response(status, 64 [('Content-type', contentType), 65 ('Content-Length', str(len(response)))]) 66 return response 66 @type start_response: callable following WSGI start_response convention 67 @param start_response: WSGI start response callable 68 @type url: basestring 69 @param url: URL to redirect to 70 @rtype: list 71 @return: empty HTML body 72 """ 73 start_response('302 %s' % httplib.responses[302], 74 [('Content-type', 'text/html'+self.charset), 75 ('Location', url)]) 76 return [] -
TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/ssl.py
r4823 r4838 22 22 import httplib 23 23 24 from ndg.security.server.wsgi import NDGSecurity MiddlewareBase24 from ndg.security.server.wsgi import NDGSecurityPathFilter 25 25 from ndg.security.common.X509 import X509Stack, X509Cert, X509CertError 26 26 27 class SSLClientAuthNMiddleware(NDGSecurity MiddlewareBase):27 class SSLClientAuthNMiddleware(NDGSecurityPathFilter): 28 28 '''Apply to SSL client authentication to configured URL paths. 29 29 … … 34 34 35 35 propertyDefaults = { 36 'errorResponseCode': 401,37 'pathMatchList': '/',38 36 'caCertFilePathList': [] 39 37 } 40 38 propertyDefaults.update(NDGSecurityPathFilter.propertyDefaults) 39 41 40 _isSSLClientCertSet = lambda self: bool(self._environ.get( 42 41 SSLClientAuthNMiddleware.sslClientCertKeyName)) 43 42 isSSLClientCertSet = property(fget=_isSSLClientCertSet, 44 43 doc="Check for client cert. set in environ") 45 46 _pathMatch = lambda self: self._path in self.pathMatchList47 pathMatch = property(fget=_pathMatch,48 doc="Check for input path match to list of paths"49 "to which SSL client AuthN is to be applied")50 51 def __init__(self, app, app_conf, prefix='', **local_conf):52 self._app = app53 54 opt = SSLClientAuthNMiddleware.propertyDefaults.copy()55 56 # If no prefix is set, there is no way to distinguish options set for57 # this app and those applying to other applications58 if app_conf is not None and prefix:59 # Update from application config dictionary - filter using prefix60 SSLClientAuthNMiddleware._filterOpts(opt, app_conf, prefix=prefix)61 62 # Similarly, filter keyword input63 SSLClientAuthNMiddleware._filterOpts(opt, local_conf, prefix=prefix)64 65 # Update options from keywords - matching app_conf ones will be66 # overwritten67 opt.update(local_conf)68 69 # Set options as object attributes70 for name, val in opt.items():71 setattr(self, name, val)72 73 def _getErrorResponseCode(self):74 """75 @rtype: int76 @return: HTTP error code set by this middleware on client cert.77 verification error78 """79 return self._errorResponseCode80 81 def _setErrorResponseCode(self, code):82 """83 @type code: int or basestring84 @param code: error response code set if client cert. verification85 fails"""86 if isinstance(code, int):87 self._errorResponseCode = code88 elif isinstance(code, basestring):89 self._errorResponseCode = int(code)90 else:91 raise TypeError('Expecting int or string type for '92 '"errorResponseCode" attribute')93 94 if self._errorResponseCode not in httplib.responses:95 raise ValueError("Error response code [%d] is not recognised "96 "standard HTTP response code" %97 self._errorResponseCode)98 99 errorResponseCode = property(fget=_getErrorResponseCode,100 fset=_setErrorResponseCode,101 doc="Response code raised if client "102 "certificate verification fails")103 44 104 45 def _setCACertsFromFileList(self, caCertFilePathList): … … 156 97 doc='List of URL paths to which to apply SSL ' 157 98 'client authentication') 158 159 @classmethod160 def _filterOpts(cls, opt, newOpt, prefix=''):161 '''Convenience utility to filter input options set in __init__ via162 app_conf or keywords163 164 @type opt: dict165 @param opt: existing options set. These will be updated by this166 method based on the content of newOpt167 @type newOpt: dict168 @param newOpt: new options to update opt with169 @type prefix: basestring170 @param prefix: if set, remove the given prefix from the input options171 @raise KeyError: if an option is set that is not in the classes172 defOpt class variable173 '''174 175 badOpt = []176 for k,v in newOpt.items():177 if prefix and k.startswith(prefix):178 subK = k.replace(prefix, '')179 filtK = '_'.join(subK.split('.'))180 else:181 filtK = k182 183 if filtK not in cls.propertyDefaults:184 badOpt += [k]185 else:186 opt[filtK] = v187 188 if len(badOpt) > 0:189 raise TypeError("Invalid input option(s) set: %s" %190 (", ".join(badOpt)))191 99 192 100 def __call__(self, environ, start_response):
Note: See TracChangeset
for help on using the changeset viewer.