That's an interesting (but understandable) requirement, which means you are
probably in for an interesting time.

Undoubtedly you'll need to roll your own authentication backend (
https://docs.djangoproject.com/en/1.7/topics/auth/customizing/#authentication-backends)
and a custom user that contains the campus as one of the attributes (
https://docs.djangoproject.com/en/1.7/topics/auth/customizing/#substituting-a-custom-user-model
).

As far as the user model inheritance goes, I would recommend inheriting
from AbstractBaseUser (
https://github.com/django/django/blob/master/django/contrib/auth/models.py#L196)
and probably the Permission mixin in that same file if you are using the
Django authorization system. Also take a look at the AbstractUser class for
hints on the other bits you may need to manually specify that are not
included in AbstractBaseUser.

However, as you've aptly pointed out, the (somewhat) tricky part is that
your authentication system requires a third piece of data that Django is
not expecting, the campus name.

When you begin overriding/implementing the various bits of the
authentication system, you'll likely need to add an additional keyword
argument like 'campus' or some other identifier such as:

def authenticate(self, username=None, password=None, campus=None):
    # do auth things related to campus


Then, any views, etc. that would run the contrib.auth's version of
authenticate() would instead call your version with the extended signature
including the campus. A quick search through the Github repo suggests that
the only place where authenticate() is called is via the built-in form/view
for logging in using the default authentication backend. You would have to
override both of these constructs as part of the custom auth backend
anyway, so you appear to be in luck. Your authentication call would look
something like authenticate(user, pass, campus).

You didn't mention anything about how each campus handles authentication
(doesn't matter for this conversation), but your authenticate() method
would likely contain a dictionary of methods that handle the actual
interaction between Django and the specific campus backend, keyed via the
campus name (you could also put this in settings.py and import it):

def _auth_campus1(self, user, pass):
    # stuff for campus 1

def _auth_campus2(self, user, pass):
    # stuff for campus 2


def authenticate(self, user,pass,campus):
    AUTH_SOURCES = {
        'campus1': _auth_campus1,
        'campus2: _auth_campus2,
    }

    if campus not in AUTH_SOURCES:
        return None

    auth_func = AUTH_SOURCES[campus]

    if auth_func(user, pass):
        # check if user exists in local Django DB, otherwise create_user()

    # other checks
    # return user or None



Once you get past the authentication portion, it looks as though the
authorization portion should work out of the box (assuming the other bits
are overridden properly per the docs), since you already have a user
object, if you plan to use it at all.

Be sure to have sane timeouts so that users aren't stuck waiting for broken
campus backends, and so that processes/threads aren't stalled when they
could be serving other users.

HTH,

-James


On Mon, Jan 19, 2015 at 12:54 PM, Erik Cederstrand <
erik+li...@cederstrand.dk> wrote:

> Hello
>
> I'm creating a Django frontend for a legacy school system. The legacy
> system has users, but usernames are only unique together with a school:
>
> class LegacyUser(models.Model):
>    school = models.ForeignKey(School)
>    username = models.CharField(max_length=40)
>
>    class Meta:
>        unique_together = ['school', 'username']
>
>
> I need to authenticate users using their school name, username and
> password, so I can serve them data connected to the LegacyUser. The legacy
> system provides an authentication service that I want to use to verify the
> password.
>
> The Django authentication model seems to revolve around the username being
> unique, so I can't just inherit the User model, login forms etc. How do I
> get the School shoe-horned into the Django auth framework, and where do I
> call the external authentication service? Some ideas how to best accomplish
> this would be great!
>
>
> Thanks,
> Erik
>
> --
> You received this message because you are subscribed to the Google Groups
> "Django users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to django-users+unsubscr...@googlegroups.com.
> To post to this group, send email to django-users@googlegroups.com.
> Visit this group at http://groups.google.com/group/django-users.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/django-users/26BA41BB-1771-4C5C-9980-A2C49F30280C%40cederstrand.dk
> .
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at http://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/CA%2Be%2BciVp_496yjFT1HsBgt-ahFyxxs6Ksxv4d3EjxXpab4WX2g%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to