Skip to content
Snippets Groups Projects
Commit 5461963c authored by Tanner Prestegard's avatar Tanner Prestegard Committed by GraceDB
Browse files

X509Cert: connect to user via ForeignKey rather than m2m relation

An X509 certificate should only map to a single user account - we
can't do authentication properly if it maps to multiple, so this
was an obviously necessary change. There are several migrations for
making this conversion in steps.
parent 1dfae374
No related branches found
No related tags found
No related merge requests found
......@@ -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'))
......
......@@ -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"""
......
......@@ -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"""
......
# -*- 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),
),
]
# -*- 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),
]
# -*- 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),
),
]
......@@ -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):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment