1 |
1 |
from optparse import make_option
|
2 |
2 |
import sys
|
3 |
3 |
import xml.etree.ElementTree as etree
|
4 |
4 |
import os
|
5 |
5 |
import requests
|
6 |
6 |
from StringIO import StringIO
|
7 |
7 |
|
8 |
|
from authentic2.compat_lasso import lasso
|
9 |
8 |
from django.core.management.base import BaseCommand, CommandError
|
10 |
|
from django.db import transaction
|
11 |
9 |
from django.template.defaultfilters import slugify
|
12 |
10 |
from django.utils.translation import gettext as _
|
13 |
11 |
|
|
12 |
from authentic2.compat import commit_on_success
|
|
13 |
from authentic2.compat_lasso import lasso
|
14 |
14 |
from authentic2.saml.models import *
|
15 |
15 |
from authentic2.saml.shibboleth.afp_parser import parse_attribute_filters_file
|
16 |
16 |
from authentic2.attribute_aggregator.core import (get_definition_from_alias,
|
17 |
17 |
get_full_definition, get_def_name_from_alias)
|
18 |
18 |
|
19 |
19 |
SAML2_METADATA_UI_HREF = 'urn:oasis:names:tc:SAML:metadata:ui'
|
20 |
20 |
|
21 |
21 |
def md_element_name(tag_name):
|
... | ... | |
229 |
229 |
action='store_true',
|
230 |
230 |
default=False,
|
231 |
231 |
help='When creating a new provider, make it disabled by default.'),
|
232 |
232 |
)
|
233 |
233 |
|
234 |
234 |
args = '<metadata_file>'
|
235 |
235 |
help = 'Load the specified SAMLv2 metadata file'
|
236 |
236 |
|
237 |
|
@transaction.commit_manually
|
|
237 |
@commit_on_success
|
238 |
238 |
def handle(self, *args, **options):
|
239 |
239 |
verbosity = int(options['verbosity'])
|
240 |
240 |
source = options['source']
|
|
241 |
if not args:
|
|
242 |
raise CommandError('No metadata file on the command line')
|
|
243 |
# Check sources
|
241 |
244 |
try:
|
242 |
|
if not args:
|
243 |
|
raise CommandError('No metadata file on the command line')
|
244 |
|
# Check sources
|
|
245 |
if source is not None:
|
|
246 |
source.decode('ascii')
|
|
247 |
except:
|
|
248 |
raise CommandError('--source MUST be an ASCII string value')
|
|
249 |
if args[0].startswith('http://') or args[0].startswith('https://'):
|
|
250 |
response = requests.get(args[0])
|
|
251 |
if not response.ok:
|
|
252 |
raise CommandError('Unable to open url %s' % args[0])
|
|
253 |
metadata_file = StringIO(response.content)
|
|
254 |
else:
|
245 |
255 |
try:
|
246 |
|
if source is not None:
|
247 |
|
source.decode('ascii')
|
|
256 |
metadata_file = file(args[0])
|
248 |
257 |
except:
|
249 |
|
raise CommandError('--source MUST be an ASCII string value')
|
250 |
|
if args[0].startswith('http://') or args[0].startswith('https://'):
|
251 |
|
response = requests.get(args[0])
|
252 |
|
if not response.ok:
|
253 |
|
raise CommandError('Unable to open url %s' % args[0])
|
254 |
|
metadata_file = StringIO(response.content)
|
255 |
|
else:
|
256 |
|
try:
|
257 |
|
metadata_file = file(args[0])
|
258 |
|
except:
|
259 |
|
raise CommandError('Unable to open file %s' % args[0])
|
|
258 |
raise CommandError('Unable to open file %s' % args[0])
|
260 |
259 |
|
261 |
|
try:
|
262 |
|
doc = etree.parse(metadata_file)
|
263 |
|
except Exception, e:
|
264 |
|
raise CommandError('XML parsing error: %s' % str(e))
|
|
260 |
try:
|
|
261 |
doc = etree.parse(metadata_file)
|
|
262 |
except Exception, e:
|
|
263 |
raise CommandError('XML parsing error: %s' % str(e))
|
|
264 |
if doc.getroot().tag == ENTITY_DESCRIPTOR_TN:
|
|
265 |
load_one_entity(doc.getroot(), options)
|
|
266 |
elif doc.getroot().tag == ENTITIES_DESCRIPTOR_TN:
|
|
267 |
afp = None
|
|
268 |
if 'attribute-filter-policy' in options and options['attribute-filter-policy']:
|
|
269 |
path = options['attribute-filter-policy']
|
|
270 |
if not os.path.isfile(path):
|
|
271 |
raise CommandError(
|
|
272 |
'No attribute filter policy file %s' % path)
|
|
273 |
afp = parse_attribute_filters_file(
|
|
274 |
options['attribute-filter-policy'])
|
|
275 |
sp_policy = None
|
|
276 |
if 'sp_policy' in options and options['sp_policy']:
|
|
277 |
sp_policy_name = options['sp_policy']
|
|
278 |
try:
|
|
279 |
sp_policy = SPOptionsIdPPolicy.objects.get(name=sp_policy_name)
|
|
280 |
if verbosity > 1:
|
|
281 |
print 'Service providers are set with the following SAML2 \
|
|
282 |
options policy: %s' % sp_policy
|
|
283 |
except:
|
|
284 |
if verbosity > 0:
|
|
285 |
print >>sys.stderr, _('SAML2 service provider options policy with name %s not found') % sp_policy_name
|
|
286 |
raise CommandError()
|
|
287 |
else:
|
|
288 |
if verbosity > 1:
|
|
289 |
print 'No SAML2 service provider options policy provided'
|
|
290 |
idp_policy = None
|
|
291 |
if 'idp_policy' in options and options['idp_policy']:
|
|
292 |
idp_policy_name = options['idp_policy']
|
|
293 |
try:
|
|
294 |
idp_policy = IdPOptionsSPPolicy.objects.get(name=idp_policy_name)
|
|
295 |
if verbosity > 1:
|
|
296 |
print 'Identity providers are set with the following SAML2 \
|
|
297 |
options policy: %s' % idp_policy
|
|
298 |
except:
|
|
299 |
if verbosity > 0:
|
|
300 |
print >>sys.stderr, _('SAML2 identity provider options policy with name %s not found') % idp_policy_name
|
|
301 |
raise CommandError()
|
|
302 |
else:
|
|
303 |
if verbosity > 1:
|
|
304 |
print _('No SAML2 identity provider options policy provided')
|
|
305 |
loaded = []
|
265 |
306 |
if doc.getroot().tag == ENTITY_DESCRIPTOR_TN:
|
266 |
|
load_one_entity(doc.getroot(), options)
|
267 |
|
elif doc.getroot().tag == ENTITIES_DESCRIPTOR_TN:
|
268 |
|
afp = None
|
269 |
|
if 'attribute-filter-policy' in options and options['attribute-filter-policy']:
|
270 |
|
path = options['attribute-filter-policy']
|
271 |
|
if not os.path.isfile(path):
|
272 |
|
raise CommandError(
|
273 |
|
'No attribute filter policy file %s' % path)
|
274 |
|
afp = parse_attribute_filters_file(
|
275 |
|
options['attribute-filter-policy'])
|
276 |
|
sp_policy = None
|
277 |
|
if 'sp_policy' in options and options['sp_policy']:
|
278 |
|
sp_policy_name = options['sp_policy']
|
279 |
|
try:
|
280 |
|
sp_policy = SPOptionsIdPPolicy.objects.get(name=sp_policy_name)
|
281 |
|
if verbosity > 1:
|
282 |
|
print 'Service providers are set with the following SAML2 \
|
283 |
|
options policy: %s' % sp_policy
|
284 |
|
except:
|
285 |
|
if verbosity > 0:
|
286 |
|
print >>sys.stderr, _('SAML2 service provider options policy with name %s not found') % sp_policy_name
|
287 |
|
raise CommandError()
|
288 |
|
else:
|
289 |
|
if verbosity > 1:
|
290 |
|
print 'No SAML2 service provider options policy provided'
|
291 |
|
idp_policy = None
|
292 |
|
if 'idp_policy' in options and options['idp_policy']:
|
293 |
|
idp_policy_name = options['idp_policy']
|
294 |
|
try:
|
295 |
|
idp_policy = IdPOptionsSPPolicy.objects.get(name=idp_policy_name)
|
296 |
|
if verbosity > 1:
|
297 |
|
print 'Identity providers are set with the following SAML2 \
|
298 |
|
options policy: %s' % idp_policy
|
299 |
|
except:
|
300 |
|
if verbosity > 0:
|
301 |
|
print >>sys.stderr, _('SAML2 identity provider options policy with name %s not found') % idp_policy_name
|
302 |
|
raise CommandError()
|
303 |
|
else:
|
304 |
|
if verbosity > 1:
|
305 |
|
print _('No SAML2 identity provider options policy provided')
|
306 |
|
loaded = []
|
307 |
|
if doc.getroot().tag == ENTITY_DESCRIPTOR_TN:
|
308 |
|
entity_descriptors = [ doc.getroot() ]
|
309 |
|
else:
|
310 |
|
entity_descriptors = doc.getroot().findall(ENTITY_DESCRIPTOR_TN)
|
311 |
|
for entity_descriptor in entity_descriptors:
|
312 |
|
try:
|
313 |
|
load_one_entity(entity_descriptor, options,
|
314 |
|
sp_policy=sp_policy, idp_policy=idp_policy,
|
315 |
|
afp=afp)
|
316 |
|
loaded.append(entity_descriptor.get(ENTITY_ID))
|
317 |
|
except Exception, e:
|
318 |
|
if not options['ignore-errors']:
|
319 |
|
raise
|
320 |
|
if verbosity > 0:
|
321 |
|
print >>sys.stderr, _('Failed to load entity descriptor for %s') % entity_descriptor.get(ENTITY_ID)
|
322 |
|
raise CommandError()
|
323 |
|
if options['source']:
|
324 |
|
if options['delete']:
|
325 |
|
print 'Finally delete all providers for source: %s...' % source
|
326 |
|
LibertyProvider.objects.filter(federation_source=source).delete()
|
327 |
|
else:
|
328 |
|
to_delete = []
|
329 |
|
for provider in LibertyProvider.objects.filter(federation_source=source):
|
330 |
|
if provider.entity_id not in loaded:
|
331 |
|
to_delete.append(provider)
|
332 |
|
for provider in to_delete:
|
333 |
|
if verbosity > 1:
|
334 |
|
print _('Deleted obsolete provider %s') % provider.entity_id
|
335 |
|
provider.delete()
|
|
307 |
entity_descriptors = [ doc.getroot() ]
|
336 |
308 |
else:
|
337 |
|
raise CommandError('%s is not a SAMLv2 metadata file' % metadata_file)
|
338 |
|
except:
|
339 |
|
transaction.rollback()
|
340 |
|
raise
|
|
309 |
entity_descriptors = doc.getroot().findall(ENTITY_DESCRIPTOR_TN)
|
|
310 |
for entity_descriptor in entity_descriptors:
|
|
311 |
try:
|
|
312 |
load_one_entity(entity_descriptor, options,
|
|
313 |
sp_policy=sp_policy, idp_policy=idp_policy,
|
|
314 |
afp=afp)
|
|
315 |
loaded.append(entity_descriptor.get(ENTITY_ID))
|
|
316 |
except Exception, e:
|
|
317 |
if not options['ignore-errors']:
|
|
318 |
raise
|
|
319 |
if verbosity > 0:
|
|
320 |
print >>sys.stderr, _('Failed to load entity descriptor for %s') % entity_descriptor.get(ENTITY_ID)
|
|
321 |
raise CommandError()
|
|
322 |
if options['source']:
|
|
323 |
if options['delete']:
|
|
324 |
print 'Finally delete all providers for source: %s...' % source
|
|
325 |
LibertyProvider.objects.filter(federation_source=source).delete()
|
|
326 |
else:
|
|
327 |
to_delete = []
|
|
328 |
for provider in LibertyProvider.objects.filter(federation_source=source):
|
|
329 |
if provider.entity_id not in loaded:
|
|
330 |
to_delete.append(provider)
|
|
331 |
for provider in to_delete:
|
|
332 |
if verbosity > 1:
|
|
333 |
print _('Deleted obsolete provider %s') % provider.entity_id
|
|
334 |
provider.delete()
|
341 |
335 |
else:
|
342 |
|
transaction.commit()
|
|
336 |
raise CommandError('%s is not a SAMLv2 metadata file' % metadata_file)
|
343 |
337 |
if not options.get('delete'):
|
344 |
338 |
if verbosity > 1:
|
345 |
339 |
print 'Loaded', options.get('count', 0), 'providers'
|
346 |
|
-
|