Add a module to perform HTTP GET with proper certificate checks

Replace all usr of urllib.urlopen by this the new function get_url.

If M2Crypto is availlable, HTTPs URLs work, if not they do not.

Closes #70
This commit is contained in:
Benjamin Dauvergne 2011-05-27 17:34:16 +02:00
parent eff4caf487
commit a9eb81ee46
3 changed files with 52 additions and 10 deletions

35
authentic2/http_utils.py Normal file
View File

@ -0,0 +1,35 @@
try:
import M2Crypto
except ImportError:
M2Crypto = None
import urllib2
from django.conf import settings
__SSL_CONTEXT = None
def get_ssl_context():
global __SSL_CONTEXT
if __SSL_CONTEXT is None:
__SSL_CONTEXT = M2Crypto.SSL.Context()
cafile = getattr(settings, 'CAFILE', '/etc/ssl/certs/ca-certificates.crt')
capath = getattr(settings, 'CAPATH', '/etc/ssl/certs/')
__SSL_CONTEXT.load_verify_locations(cafile=cafile, capath=capath)
return __SSL_CONTEXT
def get_url(url):
'''Does a simple GET on an URL, if the URL uses TLS, M2Crypto is used to
check the certificate'''
if url.startswith('https'):
if not M2Crypto:
raise urllib2.URLError('https is unsupported without M2Crypto')
try:
return M2Crypto.m2urllib2.build_opener(get_ssl_context()).open(url).read()
except M2Crypto.SSL.Checker.SSLVerificationError, e:
# Wrap error
raise urllib2.URLError('SSL Verification error %s' % e)
return urllib2.urlopen(url).read()
if __name__ == '__main__':
print get_url('https://dev.entrouvert.org')

View File

@ -1,4 +1,5 @@
import urllib
import urllib2
import logging
from django.contrib import admin
from django.utils.translation import ugettext as _
@ -14,6 +15,9 @@ from models import AuthorizationAttributeMapping, LibertyProviderPolicy
from models import LibertySessionDump, LibertyIdentityDump, LibertyFederation
from models import LibertyAssertion, LibertySessionSP, KeyValue
from models import LibertySession
from authentic2.http_utils import get_url
logger = logging.getLogger(__name__)
class AuthorizationAttributeMapAdmin(admin.ModelAdmin):
fieldsets = (
@ -130,15 +134,17 @@ def update_metadata(modeladmin, request, queryset):
for provider in queryset:
if provider.entity_id.startswith('http'):
try:
data = urllib.urlopen(provider.entity_id).read()
data = get_url(provider.entity_id)
if data != provider.metadata:
provider.metadata = data
updated.append(provider.entity_id)
provider.save()
except IOError:
pass
updated = ', '.join(updated)
messages.info(request, _('Metadata update for: %s') % updated)
except (urllib2.URLError, IOError), e:
messages.error(request, _('Failure to resolve %s: %s') %
(provider.entity_id, e))
if updated:
updated = ', '.join(updated)
messages.info(request, _('Metadata update for: %s') % updated)
class LibertyProviderAdmin(admin.ModelAdmin):
form = LibertyProviderForm

View File

@ -27,6 +27,7 @@ import saml2utils
import saml11utils
from authentic2.authsaml2 import signals
from authentic2.http_utils import get_url
AUTHENTIC_STATUS_CODE_NS = "http://authentic.entrouvert.org/status_code/"
AUTHENTIC_STATUS_CODE_UNKNOWN_PROVIDER = AUTHENTIC_STATUS_CODE_NS + \
@ -308,10 +309,10 @@ def retrieve_metadata_and_create(request, provider_id, sp_or_idp):
return None
# Try the WKL
try:
metadata = urllib.urlopen(provider_id).read()
except:
logging.error('SAML metadata autoload: failure to retrieve metadata \
for entity id %r' % provider_id)
metadata = get_url(provider_id)
except Exception, e:
logging.error('SAML metadata autoload: failure to retrieve metadata '
'for entity id %r: %s' % (provider_id, e))
return None
logger.debug('loaded %d bytes' % len(metadata))
try: