diff --git a/gracedb/api/backends.py b/gracedb/api/backends.py index 6a202e3cd336b384a7cd14cea333f7eede8550a1..9274ae56d5ee099e8ca1cdb7915a66d67e396ff9 100644 --- a/gracedb/api/backends.py +++ b/gracedb/api/backends.py @@ -157,17 +157,8 @@ class GraceDbX509Authentication(authentication.BaseAuthentication): 'subject')) cert = certs.first() - # Handle incorrect number of users for a certificate - num_users = cert.users.count() - if (num_users > 1): - raise exceptions.AuthenticationFailed(_('Multiple users have the ' - 'same certificate subject')) - elif (num_users == 0): - raise exceptions.AuthenticationFailed(_('No user found for this ' - 'certificate')) - user = cert.users.first() - # Check if user is active + user = cert.user if not user.is_active: raise exceptions.AuthenticationFailed( _('User inactive or deleted')) diff --git a/gracedb/api/tests/test_authentication.py b/gracedb/api/tests/test_authentication.py index 0b8497e3f7894949a16ceed7a64b762247762727..d1f0c9f7e9a62bb3d402865667140633e1c7d4c7 100644 --- a/gracedb/api/tests/test_authentication.py +++ b/gracedb/api/tests/test_authentication.py @@ -107,8 +107,8 @@ class TestGraceDbX509Authentication(GraceDbApiTestBase): # Set up certificate for internal user account cls.x509_subject = '/x509_subject' - cert = X509Cert.objects.create(subject=cls.x509_subject) - cert.users.add(cls.internal_user) + cert = X509Cert.objects.create(subject=cls.x509_subject, + user=cls.internal_user) def test_user_authenticate_to_api_with_x509_cert(self): """User can authenticate to API with valid X509 certificate""" diff --git a/gracedb/api/tests/test_backends.py b/gracedb/api/tests/test_backends.py index 6cbb390e322206d7f002e3ed2eface9784ccfb45..e0caec2b4f54f0527693e445d3812e2c58e4cbdd 100644 --- a/gracedb/api/tests/test_backends.py +++ b/gracedb/api/tests/test_backends.py @@ -135,8 +135,8 @@ class TestGraceDbX509Authentication(GraceDbApiTestBase): # Set up certificate for internal user account cls.x509_subject = '/x509_subject' - cert = X509Cert.objects.create(subject=cls.x509_subject) - cert.users.add(cls.internal_user) + cert = X509Cert.objects.create(subject=cls.x509_subject, + user=cls.internal_user) def test_user_authenticate_to_api_with_x509_cert(self): """User can authenticate to API with valid X509 certificate""" diff --git a/gracedb/ligoauth/migrations/0041_x509cert_add_user_foreignkey.py b/gracedb/ligoauth/migrations/0041_x509cert_add_user_foreignkey.py new file mode 100644 index 0000000000000000000000000000000000000000..4cadf8d802f8676b9ee6a11be851f3b6ff7d8edd --- /dev/null +++ b/gracedb/ligoauth/migrations/0041_x509cert_add_user_foreignkey.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.20 on 2019-06-03 18:08 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('ligoauth', '0040_x509cert_unique_subject'), + ] + + operations = [ + migrations.AddField( + model_name='x509cert', + name='user', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + migrations.AlterField( + model_name='x509cert', + name='users', + field=models.ManyToManyField(related_name='certs', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/gracedb/ligoauth/migrations/0042_populate_x509cert_user_field.py b/gracedb/ligoauth/migrations/0042_populate_x509cert_user_field.py new file mode 100644 index 0000000000000000000000000000000000000000..d05b8d1d2a9984fbb1ea069c21d5618b7d897846 --- /dev/null +++ b/gracedb/ligoauth/migrations/0042_populate_x509cert_user_field.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.20 on 2019-06-03 18:09 +from __future__ import unicode_literals + +from django.db import migrations + +def populate_user_field(apps, schema_editor): + X509Cert = apps.get_model('ligoauth', 'X509Cert') + + # Loop over all certificates, get first user, add as user ForeignKey + for cert in X509Cert.objects.iterator(): + cert.user = cert.users.first() + cert.save(update_fields=['user']) + + # Clear out users m2m field + # NOTE: this isn't exactly "safe" if there is more than one + # user associated with a certificate, but there *shouldn't* be + # (no examples found in production DB after fixing some errors), + # and even if there is, it should be cleared up after running + # the 'update_user_accounts_from_ligo_ldap' script once or twice. + cert.users.clear() + + +def populate_users_field(apps, schema_editor): + X509Cert = apps.get_model('ligoauth', 'X509Cert') + + # Loop over all certificates and add user to users m2m field + for cert in X509Cert.objects.iterator(): + cert.users.add(cert.user) + + # Clear out user ForeignKey + cert.user = None + cert.save(update_fields=['user']) + + +class Migration(migrations.Migration): + + dependencies = [ + ('ligoauth', '0041_x509cert_add_user_foreignkey'), + ] + + operations = [ + migrations.RunPython(populate_user_field, populate_users_field), + ] diff --git a/gracedb/ligoauth/migrations/0043_x509cert_delete_users_m2m_field.py b/gracedb/ligoauth/migrations/0043_x509cert_delete_users_m2m_field.py new file mode 100644 index 0000000000000000000000000000000000000000..57e4825fea99ddc9e3a092d5db51960caab9a3ae --- /dev/null +++ b/gracedb/ligoauth/migrations/0043_x509cert_delete_users_m2m_field.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.20 on 2019-06-03 18:54 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('ligoauth', '0042_populate_x509cert_user_field'), + ] + + operations = [ + migrations.RemoveField( + model_name='x509cert', + name='users', + ), + migrations.AlterField( + model_name='x509cert', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/gracedb/ligoauth/models.py b/gracedb/ligoauth/models.py index 1a5685448ede578ed0dffe7a4408f68f20fc42d5..b88e640815f0e69f77a26d30993ada5a9ab53406 100644 --- a/gracedb/ligoauth/models.py +++ b/gracedb/ligoauth/models.py @@ -26,7 +26,7 @@ class RobotUser(User): class X509Cert(models.Model): """Model for storing X.509 certificate subjects for API access""" subject = models.CharField(max_length=255, unique=True, null=False) - users = models.ManyToManyField(User) + user = models.ForeignKey(User) class AuthGroup(Group):