Changeset 4606 for TI12-security/trunk/python
- Timestamp:
- 11/12/08 17:08:31 (12 years ago)
- Location:
- TI12-security/trunk/python
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
TI12-security/trunk/python/ndg.security.common/ndg/security/common/X509.py
r4603 r4606 347 347 return x509Cert 348 348 349 #_____________________________________________________________________________350 349 # Alternative AttCert constructors 351 #352 350 def X509CertRead(filePath): 353 351 """Create a new X509 certificate read in from a file""" … … 358 356 return x509Cert 359 357 360 361 #_____________________________________________________________________________362 358 def X509CertParse(x509CertTxt): 363 359 """Create a new X509 certificate from string of file content""" … … 369 365 370 366 371 #_____________________________________________________________________________ 372 class X509StackError(Exception): 367 class X509StackError(X509CertError): 373 368 """Error from X509Stack type""" 374 369 375 #_____________________________________________________________________________ 376 class CertIssuerNotFound(X509StackError): 370 class X509StackEmptyError(X509CertError): 371 """Expecting non-zero length X509Stack""" 372 373 class X509CertIssuerNotFound(X509CertError): 377 374 """Raise from verifyCertChain if no certificate can be found to verify the 378 375 input""" 379 376 380 class SelfSignedCert(X509 StackError):377 class SelfSignedCert(X509CertError): 381 378 """Raise from verifyCertChain if cert. is self-signed and 382 379 rejectSelfSignedCert=True""" 380 381 class X509CertInvalidSignature(X509CertError): 382 """X.509 Certificate has an invalid signature""" 383 383 384 #_____________________________________________________________________________385 384 class X509Stack(object): 386 385 """Wrapper for M2Crypto X509_Stack""" … … 479 478 # populated 480 479 if n2Validate == 0: 481 raise X509StackE rror, \482 "Empty stack and no x509Cert2Verify set: no cert.s to verify"480 raise X509StackEmptyError("Empty stack and no x509Cert2Verify " 481 "set: no cert.s to verify") 483 482 484 483 x509Cert2Verify = self[-1] … … 505 504 # signature of the cert. to be verified 506 505 if not x509Cert2Verify.verify(issuerX509Cert.pubKey): 507 X509Cert Error, 'Signature is invalid for cert. "%s"' % \508 x509Cert2Verify.dn506 X509CertInvalidSignature('Signature is invalid for cert. ' 507 '"%s"' % x509Cert2Verify.dn) 509 508 510 509 # In the next iteration the issuer cert. will be checked: … … 525 524 # If only one iteration occured then it must be a self 526 525 # signed certificate 527 raise SelfSignedCert, "Certificate is self signed" 526 raise SelfSignedCert("Certificate is self signed: [DN=%s]" % 527 issuerX509Cert.dn) 528 528 529 529 if not caX509Stack: … … 531 531 532 532 elif not caX509Stack: 533 raise CertIssuerNotFound, \534 'No issuer cert. found for cert. "%s"'%x509Cert2Verify.dn533 raise X509CertIssuerNotFound('No issuer cert. found for cert. ' 534 '"%s"' % x509Cert2Verify.dn) 535 535 536 536 for caCert in caX509Stack: … … 542 542 if issuerX509Cert: 543 543 if not x509Cert2Verify.verify(issuerX509Cert.pubKey): 544 X509Cert Error, 'Signature is invalid for cert. "%s"' % \545 x509Cert2Verify.dn544 X509CertInvalidSignature('Signature is invalid for cert. "%s"'% 545 x509Cert2Verify.dn) 546 546 547 547 # Chain is validated through to CA cert 548 548 return 549 549 else: 550 raise CertIssuerNotFound, 'No issuer cert. found for cert. "%s"'%\551 x509Cert2Verify.dn550 raise X509CertIssuerNotFound('No issuer cert. found for ' 551 'certificate "%s"'%x509Cert2Verify.dn) 552 552 553 553 # If this point is reached then an issuing cert is missing from the 554 554 # chain 555 raise X509CertError, 'Can\'t find issuer cert "%s" for cert "%s"' % \ 556 (x509Cert2Verify.issuer, x509Cert2Verify.dn) 555 raise X509CertIssuerNotFound('Can\'t find issuer cert "%s" for ' 556 'certificate "%s"' % 557 (x509Cert2Verify.issuer, 558 x509Cert2Verify.dn)) 557 559 558 560 -
TI12-security/trunk/python/ndg.security.server/ndg/security/server/wsgi/sslclientauthn.py
r4603 r4606 1 """SSL Client Authentication Middleware 2 3 Apply to SSL client authentication to configured URL paths. 4 5 SSL Client certificate is expected to be present in environ as SSL_CLIENT_CERT 6 key as set by standard Apache SSL. 7 8 NERC Data Grid Project 9 10 This software may be distributed under the terms of the Q Public License, 11 version 1.0 or later. 12 """ 13 __author__ = "P J Kershaw" 14 __date__ = "11/12/08" 15 __copyright__ = "(C) 2008 STFC & NERC" 16 __contact__ = "Philip.Kershaw@stfc.ac.uk" 17 __revision__ = "$Id$" 1 18 import logging 2 19 log = logging.getLogger(__name__) 3 from ndg.security.common.X509 import X509Cert 20 import httplib 21 from ndg.security.common.X509 import X509Cert, X509CertError 4 22 5 23 class SSLClientAuthNMiddleware(object): … … 17 35 isSSLClientCertSet = property(fget=_isSSLClientCertSet, 18 36 doc="Check for client cert. set in environ") 37 38 _pathMatch = lambda self: self._path in self.pathMatchList 39 pathMatch = property(fget=_pathMatch, 40 doc="Check for input path match to list of paths" 41 "to which SSL client AuthN is to be applied") 19 42 20 43 def __init__(self, app, app_conf, prefix='', **local_conf): … … 58 81 raise TypeError('Expecting int or string type for ' 59 82 '"errorResponseCode" attribute') 83 84 if self._errorResponseCode not in httplib.responses: 85 raise ValueError("Error response code [%d] is not recognised " 86 "standard HTTP response code" % 87 self._errorResponseCode) 60 88 61 89 errorResponseCode = property(fget=_getErrorResponseCode, … … 145 173 146 174 def __call__(self, environ, start_response): 175 176 self._path = environ.get('PATH_INFO').rstrip('/') 177 178 if not self.pathMatch: 179 return self._setResponse() 180 147 181 self._environ = environ 148 self._path = environ.get('PATH_INFO').rstrip('/') 149 150 if self.sslClientCertSet: 151 self.verifyClientCert() 152 182 183 if not self.sslClientCertSet: 184 return self._setErrorResponse() 185 186 if self.isValidClientCert(): 187 return self._setResponse() 188 else: 189 return self._setErrorResponse() 190 191 def _setResponse(self): 153 192 if self._app: 154 193 return self._app(environ, start_response) 155 194 else: 156 response = 'No app set for SSLClientAuthNMiddleware' 157 start_response('200 OK', 195 response = 'No application set for SSLClientAuthNMiddleware' 196 status = '%d %s' % (404, httplib.responses[404]) 197 start_response(status, 158 198 [('Content-type', 'text/plain'), 159 199 ('Content-Length', str(len(response)))]) 160 200 return response 161 162 def verifyClientCert(self): 201 202 def _setErrorResponse(self, msg='Invalid SSL client certificate'): 203 response = msg 204 status = '%d %s' % (self.errorResponseCode, 205 httplib.responses[self.errorResponseCode]) 206 207 start_response(status, 208 [('Content-type', 'text/plain'), 209 ('Content-Length', str(len(response)))]) 210 return response 211 212 def isValidClientCert(self): 163 213 x509Cert = X509Cert.Parse(filePath) 164 214 165 215 if len(self._caCertStack) == 0: 216 log.warning("No CA certificates set for Client certificate " 217 "signature verification") 218 else: 219 try: 220 self._caCertStack.verifyCertChain(x509Cert2Verify=x509Cert) 221 222 except X509CertError, e: 223 log.info("Client certificate verification failed: %s" % e) 224 return False 225 226 except Exception, e: 227 log.error("Client certificate verification failed with " 228 "unexpected error: %s" % e) 229 return False 230 231 return True 232 233 234 # Utility functions to support Paste Deploy application and filter function 235 # signatures 166 236 def filter_app_factory(app, app_conf, **local_conf): 237 '''Wrapper to SSLClientAuthNMiddleware for Paste Deploy filter''' 167 238 return SSLClientAuthNMiddleware(app, app_conf, **local_conf) 168 239 169 240 def app_factory(app_conf, **local_conf): 241 '''Wrapper to SSLClientAuthNMiddleware for Paste Deploy app''' 170 242 return SSLClientAuthNMiddleware(None, app_conf, **local_conf)
Note: See TracChangeset
for help on using the changeset viewer.