wip/43968-IntegrityError-duplicate-key-val (#43968) #37

Open
bdauvergne wants to merge 2 commits from wip/43968-IntegrityError-duplicate-key-val into main
2 changed files with 104 additions and 42 deletions

View File

@ -139,10 +139,14 @@ class Command(hobo_deploy.Command):
if not service.get('saml-sp-metadata-url'):
service['$done'] = True
continue
sp_url = service['saml-sp-metadata-url']
# retrieve SAML's metadata
metadata_url = service['saml-sp-metadata-url']
metadata_text = None
try:
metadata_response = requests.get(sp_url, verify=app_settings.A2_VERIFY_SSL, timeout=5)
metadata_response = requests.get(
metadata_url, verify=app_settings.A2_VERIFY_SSL, timeout=5
)
metadata_response.raise_for_status()
# verify metadata is correct
if self.check_saml_metadata(metadata_response.text):
@ -155,36 +159,63 @@ class Command(hobo_deploy.Command):
continue
metadata_text = metadata_response.text
# retrieve or intialize new a LibertyProvider model
provider, service_created = None, False
for legacy_urls in service.get('legacy_urls', []):
try:
provider = LibertyProvider.objects.get(
entity_id=legacy_urls['saml-sp-metadata-url'],
protocol_conformance=lasso.PROTOCOL_SAML_2_0,
)
provider.entity_id = sp_url
break
except LibertyProvider.DoesNotExist:
pass
if not provider:
provider, service_created = LibertyProvider.objects.get_or_create(
entity_id=sp_url, protocol_conformance=lasso.PROTOCOL_SAML_2_0
try:
# get from legacy metadata url or new metadata url
saml_sp_metadata_urls = [
urls['saml-sp-metadata-url'] for urls in service.get('legacy_urls', [])
] + [metadata_url]
provider = LibertyProvider.objects.get(
entity_id__in=saml_sp_metadata_urls,
protocol_conformance=lasso.PROTOCOL_SAML_2_0,
)
provider.name = service['title']
provider.slug = service['slug']
provider.federation_source = 'hobo'
provider.metadata = metadata_text
provider.metadata_url = service['saml-sp-metadata-url']
except LibertyProvider.DoesNotExist:
provider, service_created = LibertyProvider.objects.get_or_create(
entity_id=metadata_url, protocol_conformance=lasso.PROTOCOL_SAML_2_0
)
if service_created:
LibertyServiceProvider.objects.create(
liberty_provider=provider,
enabled=True,
sp_options_policy=policy,
users_can_manage_federations=False,
)
# initialize or update provider's fields
to_update = {
'name': service['title'],
'slug': service['slug'],
'federation_source': 'hobo',
'metadata': metadata_text,
'metadata_url': metadata_url,
'entity_id': metadata_url,
}
# choose a target ou
variables = service.get('variables', {})
if variables.get('ou-slug'):
ou, created = OrganizationalUnit.objects.get_or_create(
slug=service['variables']['ou-slug']
)
ou.name = service['variables']['ou-label']
ou.save()
try:
ou = OrganizationalUnit.objects.get(
slug=service['variables']['ou-slug'],
name=service['variables']['ou-label'],
)
created = False
except OrganizationalUnit.DoesNotExist:
ou, created = OrganizationalUnit.objects.update_or_create(
slug=service['variables']['ou-slug'],
defaults={
'name': service['variables']['ou-label'],
},
)
if created:
logging.info('hobo_deploy: created organizational unit "%s"', ou.name)
if service.get('secondary') and variables.get('ou-label'):
# for secondary services include collectivity in label
provider.name = '%s (%s)' % (service['title'], service['variables']['ou-label'])
to_update['name'] = '%s (%s)' % (
service['title'],
service['variables']['ou-label'],
)
else:
# if there are more than one w.c.s. service we will create an
# ou of the same name
@ -201,21 +232,52 @@ class Command(hobo_deploy.Command):
break
if create_ou:
ou, created = OrganizationalUnit.objects.get_or_create(name=service['title'])
# compute provider's fields to update
# update = [(field_name, old_value, new_value), ...]
update = []
for key, value in to_update.items():
if getattr(provider, key) != value:
update.append((key, getattr(provider, key), value))
# only update ou if provider is new or ou is not defined
if service_created or not provider.ou:
provider.ou = ou
update.append(('ou', None, ou))
provision_target_ous[provider.ou.id] = provider.ou
# update provider's fields
if update:
for key, dummy, new_value in update:
setattr(provider, key, new_value)
provider.save()
if service_created:
logging.info(
'hobo_deploy: created liberty provider "%s" (%s)',
metadata_url,
', '.join(f'{key}={new_value}"' for key, dummy, new_value in update),
)
else:
logging.info(
'hobo_deploy: updated liberty provider "%s" (%s)',
metadata_url,
', '.join(
f'{key} "{old_value}" => "{new_value}"'
for key, old_value, new_value in update
),
)
# update ou's home_url
if service.get('template_name') == 'portal-user':
provider.ou.home_url = service['base_url']
provider.ou.save()
provider.save()
if service_created:
service_provider = LibertyServiceProvider(
enabled=True,
liberty_provider=provider,
sp_options_policy=policy,
users_can_manage_federations=False,
)
service_provider.save()
if provider.ou.home_url != service['base_url']:
old_home_url = provider.ou.home_url
provider.ou.home_url = service['base_url']
provider.ou.save()
logging.info(
'hobo_deploy: updated ou "%s" home url from "%s" to "%s"',
provider.ou,
old_home_url,
service['base_url'],
)
# add a superuser role for the service
name = _('Superuser of %s') % service['title']
@ -268,8 +330,10 @@ class Command(hobo_deploy.Command):
for service in services:
if not service.get('$done'):
last_error = service['$last-error']
sp_url = service['saml-sp-metadata-url']
self.stderr.write(self.style.WARNING('Error registering %s: %s\n' % (sp_url, last_error)))
metadata_url = service['saml-sp-metadata-url']
self.stderr.write(
self.style.WARNING('Error registering %s: %s\n' % (metadata_url, last_error))
)
def load_skeleton(self, provider, service_id, template_name, create_ou=False):
if not getattr(settings, 'HOBO_SKELETONS_DIR', None):

View File

@ -71,8 +71,6 @@ deps:
pytest-freezegun
xmlschema<1.1
enum34<=1.1.6
psycopg2<2.9
psycopg2-binary<2.9
sorl-thumbnail
Pillow
black: pre-commit